Python
Thứ Ba, 22/01/2019, 00:01
Xem tất cả các thuộc tính, phương thức, module con của một đối tượng trong Python

Xem tất cả các thuộc tính, phương thức, module con của một đối tượng trong Python

Đã bao giờ bạn muốn sử dụng một phương thức (hoặc thuộc tính) của một đối tượng nhưng lại không nhớ chính xác tên của phương thức (hoặc thuộc tính) đó? Có thể bạn sẽ trả lời rằng: cần gì phải nhớ, vì đã có editor "nhắc".
Đúng vậy, hầu hết những editor hiện nay đều có gợi ý lệnh rất tốt. Ví dụ sau khi đã có biến A ở trong chương trình, ở những câu lệnh phía sau bạn chỉ cần gõ A. (A kèm theo một dấu chấm) thì lập tức editor sẽ xổ ra một danh sách những phương thức hoặc thuộc tính sẵn có của biến đó. Rất tiện lợi.
Tuy nhiên, đôi khi bạn cần in ra một danh sách đầy đủ những phương thức/thuộc tính của một đối tượng thì chắc chắn trình gợi ý của editor không thể giúp được bạn rồi (trừ khi bạn xem danh sách gợi ý rồi gõ lại). Hoặc trong đơn giản là bạn chỉ muốn dùng Terminal cho... "ngầu", thì gợi ý sau đây sẽ giúp bạn.

1. Thuộc tính __dict__

Trong Python, rất nhiều đối tượng (kể cả đối tượng dựng sẵn hay đối tượng tự định nghĩa) có thuộc tính __dict__. Thuộc tính này là một dictionary nội bộ, mô tả thông tin về đối tượng. Ví dụ
import pprint.pprint import numpy class Monday(): """Thu hai""" name = "2" pass >>> pprint(Monday.__dict__) {'__doc__': 'Thu hai', '__module__': '__main__', 'name': 2} >>> pprint(numpy.__dict__) {'ALLOW_THREADS': 1, 'AxisError': <class 'numpy.core._internal.AxisError'>, 'BUFSIZE': 8192, 'CLIP': 0, 'ComplexWarning': <class 'numpy.core.numeric.ComplexWarning'>, 'DataSource': <class 'numpy.lib._datasource.DataSource'>, 'ERR_CALL': 3, 'ERR_DEFAULT': 521, 'ERR_IGNORE': 0, 'ERR_LOG': 5, 'ERR_PRINT': 4, 'ERR_RAISE': 2, 'ERR_WARN': 1, 'FLOATING_POINT_SUPPORT': 1, 'FPE_DIVIDEBYZERO': 1, 'FPE_INVALID': 8, ..... 'where': <built-in function where>, 'who': <function who at 0x7f0d163d3f50>, 'zeros': <built-in function zeros>, 'zeros_like': <function zeros_like at 0x7f0d175daed8>} >>> len(numpy.__dict__) 619
Như ta thấy, những thuộc tính của class Monday vừa định nghĩa có thể nhìn thấy bằng cách truy cập Monday.__dict__ . Tương tự, tất cả thuộc tính và hàm của thư viện numpy cũng được liệt kê trong numpy.__dict__.
Nhân tiện, hàm pprint trong module pprint (pretty print) giúp ta in danh sách theo từng hàng cho dễ nhìn.
Trước khi trình bày cách lọc riêng methods và attributes trong từ điển .__dict__, ta nói thêm về một hàm rất hữu ích của Python cũng giúp ta có một danh sách tương tự, bởi vì không phải đối tượng nào cũng có thuộc tính .__dict__

2. Hàm dir()

Hàm dir() là một trong trong 76 hàm dựng sẵn của Python (Python built-in functions). Hàm này không trả về một từ điển như thuộc tính .__dict__, mà trả về một **danh sách **(trong nhiều trường hợp, chính là danh sách các keys của .__dict__).
dir() có hai cách sử dụng là: có tham số và không có tham số.
Khi chạy dir() không có tham số thì hàm sẽ trả về danh sách các biến/modules,... (tóm lại là các names) đang có trong bộ nhớ. Ví dụ:
>>> dir() ['A', 'D', 'Monday', 'Q', 'S', 'W', '__builtins__', '__doc__', '__name__', '__package__', 'addressof', 'attr', 'm', 'method', 'np', 'os', 'pd', 'pprint', 'train']
Khi truyền vào hàm một object thì hàm sẽ cố gắng trả về danh sách tất cả các thuộc tính/phương thức của object đó. Ví dụ khi ta muốn xem tất cả các thuộc tính/hàm của numpy, ta chỉ cần "dir nó" như sau:
>>> pprint(dir(numpy)) ['ALLOW_THREADS', 'AxisError', 'BUFSIZE', 'CLIP', 'ComplexWarning', 'DataSource', 'ERR_CALL', 'ERR_DEFAULT', 'ERR_IGNORE', 'ERR_LOG', 'ERR_PRINT', .... 'vsplit', 'vstack', 'warnings', 'where', 'who', 'zeros', 'zeros_like'] >>> len(dir(numpy)) 619

3. Một số hàm và module hữu ích khác

3.1 Hàm callable()

Là một trong 76 hàm built-in của Python. Trả về True nếu tham số truyền vào là *gọi được (tức là cái nào là gọi đượcnhư một hàm). *Trả về False nếu tham số truyền vào không thể gọi được. Tuy nhiên, lưu ý nếu callable(name) trả về True thì cũng chưa chắc name là tên một method mà có thể là tên một class, vì đối với Python, class là gọi được (trả về một instance).

3.2 Hàm getattr()

Là một trong 76 built-in functions của Python. Hàm này nhận hai tham số:
  • Tham số thứ nhất là một đối tượng
  • Tham số thứ 2 là tên thuộc tính hoặc tên phương thức của đối tượng (một string)
Nếu tên thuộc tính (hoặc phương thức) mà ta cung cấp nằm trong danh sách có sẵn của đối tượng thì thuộc tính/phương thức đó sẽ được gọi. Ví dụ: getattr(Monday,'name') sẽ tương đương với gọi Monday.name

3.3 Module types

Module này giúp định nghĩa tên cho tất cả những kí hiệu kiểu (tức là các kí hiệu <type 'module'>, <type 'classobj'>, <type 'str'>,...) trong Python, thay vì truy cập thuộc tính private __name__. Ví dụ:
>>> import types >>> Liz = [1, 2, 3, 4, 5] # Kiểm tra kiểu của Liz >>> type(Liz) <type 'list'> # Kiểm tra tên của kiểu của Liz >>> type(Liz).__name__ == 'list' True # Kiểm tra tên của kiểu của Liz (sử dụng module types) >>> type(Liz) == types.ListType True

4. In danh sách các methods

Như vậy, sau khi đã có danh sách các thuộc tính/phương thức của một đối tượng, ví dụ numpy, bằng hàm dir() ta chỉ cần kiểm tra xem trong danh sách này cái nào là *callable *(tạm thời chưa cần phân biệt chính xác method và class) như sau:
>>> M = [method for method in dir(numpy) if callable(getattr(numpy, method))] >>> pprint(M) 'AxisError', 'ComplexWarning', 'DataSource', 'MachAr', 'ModuleDeprecationWarning', 'PackageLoader', .... 'vsplit', 'vstack', 'where', 'who', 'zeros', 'zeros_like' >>> len(M) 517
Ta thấy, danh sách M đã rút gọn hơn so với danh sách do dir cung cấp (517 so với 619). Đây chính là danh sách những cái tên *callable, *tức là những cái tên mà numpy gọi được như một method.
Cuối cùng, để loại bỏ những cái tên là class, ta dùng thêm module **types **để kiểm tra kiểu như sau:
>>> methods = [m for m in M if type(getattr(numpy,m)) != types.ClassType] >>> pprint(methods) 'AxisError', 'ComplexWarning', 'DataSource', ... 'where', 'who', 'zeros', 'zeros_like'] >>> len(methods) 517
Như vậy ta thấy, những cái callable trong dir(numpy) chỉ có hoặc là function hoặc là method mà không có class.

5. Practise: numpy có bao nhiêu module con?

Kết hợp những hàm phía trên và thêm điều kiện lọc "not starts with _", như sau:
>>> import numpy >>> import types # Danh sách các modules của thư viện numpy >>> modules = [m for m in dir(numpy) if type(getattr(numpy,m)) == types.ModuleType and not(m.startswith('_'))] ['add_newdocs', 'char', 'compat', 'core', 'ctypeslib', 'emath', 'fft', 'lib', 'linalg', 'ma', 'math', 'matrixlib', 'os', 'polynomial', 'random', 'rec', 'sys', 'testing', 'version', 'warnings'] >>> len(modules) 20
Ta có thể thấy trong danh sách trên một số modules rất quan trọng như: mathosrandom, ...

6. Kết luận

Chúng ta vừa biết thêm về một số thuộc tính và hàm đặc biệt của Python.
  • __dict__: Từ điển nội bộ của một object (không phải cái nào cũng có)
  • dir(): Trả về danh sách thuộc tính/phương thức của object
  • callable(): Kiểm tra xem object có gọi được một cái tên nào đó hay không
  • getattr(): Một cách khác để gọi thuộc tính/phương thức của đối tượng
  • Module types: Module giúp quản lí tên của các kiểu gốc trong Python
Và cuối cùng, chúng ta biết cách để liệt kê các phương thức, thuộc tính, module con, class con,... của một object bất kì bằng cách kết hợp các hàm/module phía trên.

7. Tài liệu tham khảo

 
 
TEXmath
Cùng chủ đề