2009-06-11 43 views
41

Có sự khác biệt giữa dir(…)vars(…).keys() bằng Python không?Sự khác biệt giữa dir (…) và vars (…) .keys() bằng Python?

(Tôi hy vọng có một sự khác biệt, bởi vì nếu không điều này sẽ phá vỡ cơ chế "một cách để làm điều đó" nguyên tắc ... :)

+8

Để rõ ràng, nguyên tắc là "Một * Rõ ràng * cách để làm điều đó", không phải "* chỉ * một cách để làm điều đó". –

+0

@EthanFurman: right :) – EOL

Trả lời

67

Đối tượng Python lưu các biến mẫu trong từ điển thuộc về đối tượng. vars(x) trả lại từ điển này (cũng như x.__dict__). Mặt khác, dir(x) trả về một từ điển thuộc tính của thuộc tính của lớp là x và đệ quy các thuộc tính của các lớp cơ sở của lớp. "

Khi bạn truy cập thuộc tính của đối tượng bằng toán tử dấu chấm, python thực hiện nhiều hơn là chỉ tìm kiếm thuộc tính trong từ điển đối tượng đó. Trường hợp phổ biến là khi x là đối tượng của lớp C và bạn gọi phương thức m trên đó.

class C(object): 
    def m(self): 
     print "m" 

x = C() 
x.m() 

Phương pháp m không được lưu trữ trong x.__dict__. Nó là một thuộc tính của lớp C. Khi bạn gọi x.m(), python sẽ bắt đầu bằng cách tìm kiếm m trong x.__dict__, nhưng nó sẽ không tìm thấy nó. Tuy nhiên, nó biết rằng x là một ví dụ của C, do đó, nó sẽ tiếp theo tìm trong C.__dict__, tìm thấy nó ở đó, và gọi m với x làm đối số đầu tiên.

Vì vậy, sự khác biệt giữa vars(x)dir(x)dir(x) làm công việc thêm tìm kiếm trong x 'lớp s (và các căn cứ của nó) cho các thuộc tính có thể truy cập từ nó, không chỉ những thuộc tính được lưu trữ trong x' s riêng bảng biểu tượng. Trong ví dụ trên, vars(x) trả về một từ điển trống, vì x không có biến mẫu.Tuy nhiên, lợi nhuận dir(x)

['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', 
'__hash__', '__init__', '__module__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'm'] 
+6

Tôi sẽ thêm rằng 'dir()' cũng trả về các khe, trong khi 'vars()' thì không. – EOL

+2

Cũng có thể tùy chỉnh đầu ra của 'dir' bằng cách thực hiện phương thức ma thuật' __dir__': 'lớp A: def __dir __ (self): return ['a']' và sau đó bạn có 'dir (A()) == ['a'] 'trong khi' vars (A()) == {} '. – Bakuriu

23

Các tài liệu đã này để nói về dir:

Không có đối số, hãy trả về danh sách tên trong phạm vi cục bộ hiện tại. Với một đối số, cố gắng trả về một danh sách các thuộc tính hợp lệ cho đối tượng đó.

Và đây về vars:

Nếu không có đối số, trả về một từ điển tương ứng với bảng ký hiệu cục bộ hiện hành. Với một đối tượng mô-đun, lớp hoặc đối tượng lớp làm đối số (hoặc bất kỳ đối tượng nào khác có thuộc tính __dict__), trả về một từ điển tương ứng với bảng biểu tượng của đối tượng.

Nếu bạn không thấy sự khác biệt, có lẽ đây sẽ cho bạn thấy nhiều hơn:

>>> dir(list) 
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delsli 
ce__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getit 
em__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', 
'__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__r 
educe__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__' 
, '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'a 
ppend', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort' 
] 
>>> vars(list).keys() 
['__getslice__', '__getattribute__', 'pop', 'remove', '__rmul__', '__lt__', '__s 
izeof__', '__init__', 'count', 'index', '__delslice__', '__new__', '__contains__ 
', 'append', '__doc__', '__len__', '__mul__', 'sort', '__ne__', '__getitem__', ' 
insert', '__setitem__', '__add__', '__gt__', '__eq__', 'reverse', 'extend', '__d 
elitem__', '__reversed__', '__imul__', '__setslice__', '__iter__', '__iadd__', ' 
__le__', '__repr__', '__hash__', '__ge__'] 

Nếu bạn không có cảm giác như đọc qua đó, dir bao gồm các thuộc tính trong khi vars không:

>>> set(dir(list)).difference(vars(list).keys()) 
set(['__str__', '__reduce__', '__subclasshook__', '__setattr__', '__reduce_ex__' 
, '__format__', '__class__', '__delattr__']) 
+1

Tôi đoán rằng "bảng biểu tượng" là thuật ngữ chính, ở đây. Nó là khá khó để tìm định nghĩa của nó trong tài liệu Python chính thức (trên thực tế, tôi vẫn chưa tìm thấy nó :)). – EOL

3

Ngoài Answers nhất định, tôi muốn nói thêm rằng, sử dụng VAR() với trường hợp xây dựng trong các loại sẽ cung cấp cho báo lỗi, như trường hợp xây dựng trong các loại không có __dict__ thuộc tính.

ví dụ:

In [96]: vars([]) 
--------------------------------------------------------------------------- 

TypeError Traceback (most recent call last) 
<ipython-input-96-a6cdd8d17b23> in <module>() 
     ----> 1 vars([]) 
TypeError: vars() argument must have __dict__ attribute 
+0

'vars (danh sách)' hoạt động tốt cho tôi trong Python 2.7. – SiHa

+0

@SiHa, Nó thực sự là thể hiện của các kiểu dựng sẵn, không có thuộc tính '__dict__'. Cảm ơn vì đã sửa tôi. Tôi đã cập nhật câu trả lời. –

+0

Điểm tốt. Ngoài ra, các cá thể của các lớp tùy chỉnh thực hiện [\ _ \ _ slots \ _ \ _] (http://stackoverflow.com/questions/472000/usage-of-slots) không có thuộc tính \ _ \ _ dict \ _ \ _ hoặc tương tự sẽ đưa ra một lỗi. –

Các vấn đề liên quan