Làm thế nào để liệt kê các thuộc tính của đối tượng trong Python?


133

IC # chúng tôi làm điều đó thông qua sự phản ánh. Trong Javascript, nó đơn giản như:

for(var propertyName in objectName)
    var currentPropertyValue = objectName[propertyName];

Làm thế nào để làm điều đó trong Python?



3
Xin lưu ý rằng câu hỏi này là một cách viết sai. Hầu hết các câu trả lời là về việc liệt kê các thành viên . Tôi đang tìm cách để liệt kê các thuộc tính , tức là các thành viên của một lớp được trang trí @property.
Tomasz Gandor

Câu trả lời:


153
for property, value in vars(theObject).iteritems():
    print property, ": ", value

Xin lưu ý rằng trong một số trường hợp hiếm hoi có một __slots__tài sản, các lớp như vậy thường không có __dict__.


1
Bây giờ làm thế nào để thay đổi giá trị? trong Javascript bạn có thể làm: object [property] = newValue. Làm thế nào để làm điều đó trong Python?
Jader Dias

39
sử dụng setattr () thay thế.
Nelson

1
@Nelson Bạn có thể giải thích tại sao đó là một lựa chọn tốt hơn? Nó chỉ ngắn hơn, hoặc có những cân nhắc bổ sung?
WhyNotHugo

8
@Hugo: Đầu tiên bởi vì nó là "pythonic", nói cách khác, đó là cú pháp mà phần lớn cộng đồng đang mong đợi được thấy. Cú pháp khác có thể sẽ không cần thiết phải tạm dừng cho bất kỳ ai đọc mã của bạn. Thứ hai, một số loại thực hiện một setter __setattr__(). Đặt giá trị trực tiếp trên từ điển bỏ qua bộ setter của đối tượng (và / hoặc cha mẹ của nó). Điều khá phổ biến ở python là nhiều thứ hơn mắt thường xảy ra trong nền trong khi cài đặt thuộc tính (ví dụ như vệ sinh), sử dụng setattr()đảm bảo rằng bạn không bỏ lỡ hoặc buộc phải tự xử lý chúng một cách rõ ràng.
Michael Ekoka

3
@ Hi-Angel Điều đó không hoạt động. Tuy nhiên, cái không hoạt động là chòm sao của các định kiến ​​và giả định mà bạn có trạng thái xung quanh so với các thành viên đối tượng động trong Python. vars()chỉ trả về các thành viên tĩnh (nghĩa là các thuộc tính và phương thức đối tượng đã đăng ký với đối tượng đó __dict__). Nó không trả về các thành viên động (nghĩa là các thuộc tính và phương thức đối tượng được xác định động bởi __getattr__()phương thức của đối tượng đó hoặc phép thuật tương tự). Trong tất cả khả năng, file.ImplementationNametài sản mong muốn của bạn được xác định động và do đó không có sẵn cho vars()hoặc dir().
Cecil Curry

69

Xem inspect.getmembers(object[, predicate]).

Trả về tất cả các thành viên của một đối tượng trong danh sách các cặp (tên, giá trị) được sắp xếp theo tên. Nếu đối số vị từ tùy chọn được cung cấp, chỉ các thành viên mà vị từ trả về giá trị thực mới được đưa vào.

>>> [name for name,thing in inspect.getmembers([])]
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', 
'__delslice__',    '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', 
'__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', 
'__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__','__reduce_ex__', 
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', 
'__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 
'insert', 'pop', 'remove', 'reverse', 'sort']
>>> 

Vâng, câu trả lời này là tuyệt vời; không bao giờ sử dụng mô-đun này trước đây. getmembers () được thực hiện bằng cách chỉ cần đi bộ kết quả của dir (object), btw.
Nelson

Bạn có thể giải thích tại sao điều này tốt hơn là truy cập dict ? Tài liệu Python ít hữu ích hơn, đặc biệt là vì thông thường nó sử dụng thuật ngữ attributesthay vì members(có sự khác biệt nào giữa hai tài liệu này không?). Họ có thể đã sửa tên trong Python 3.0 để làm cho nó phù hợp.
nikow

Rất tiếc, có nghĩa là __dict__, xin lỗi.
nikow

4
@nikow: notify.getmembers () được đảm bảo tiếp tục hoạt động ngay cả khi các chi tiết nội bộ thay đổi.
Georg Schölly

3
@NicholasKnight inspect.getmembers()kết dir()hợp với các lợi ích phụ (hầu hết không đáng kể) của (A) bao gồm các thuộc tính lớp độngthuộc tính siêu dữ liệu(B) không bao gồm các thành viên không khớp với vị từ đã qua. Ngáp phải không? inspect.getmembers()là thích hợp cho các thư viện bên thứ ba hỗ trợ chung cho tất cả các loại đối tượng có thể. Đối với các trường hợp sử dụng tiêu chuẩn, tuy nhiên, dir()hoàn toàn đủ.
Cecil Curry

66

dir()là cách đơn giản. Xem tại đây:

Hướng dẫn về nội quan Python


2
Một vài điều cần lưu ý từ các tài liệu Python, bởi vì dir () được cung cấp chủ yếu để thuận tiện cho việc sử dụng tại một dấu nhắc tương tác, nó cố gắng cung cấp một tập hợp các tên thú vị hơn là cố gắng cung cấp một tập hợp các tên được xác định chặt chẽ hoặc nhất quán và hành vi chi tiết của nó có thể thay đổi trên các bản phát hành. Ví dụ, các thuộc tính siêu dữ liệu không có trong danh sách kết quả khi đối số là một lớp.
skyler

1
Câu trả lời này là tốt nhất khi thực hiện công việc cào trên cli.

15 năm trăn (công việc không toàn thời gian bao giờ) và tôi vẫn quên dir()cảm ơn bạn.
Abhishek Dujari

14

Các __dict__tài sản của đối tượng là một cuốn từ điển của tất cả các thuộc tính được định nghĩa khác của nó. Lưu ý rằng các lớp Python có thể ghi đè getattr và tạo ra những thứ trông giống như các thuộc tính nhưng không có trong đó __dict__. Ngoài ra còn có các hàm dựng sẵn vars()dir()khác nhau theo những cách tinh tế. Và __slots__có thể thay thế __dict__trong một số lớp học bất thường.

Các đối tượng rất phức tạp trong Python. __dict__là nơi thích hợp để bắt đầu lập trình kiểu phản chiếu. dir()là nơi để bắt đầu nếu bạn hack xung quanh trong một vỏ tương tác.


print vars.__doc__chỉ ra rằng With an argument, equivalent to object.__dict__sự khác biệt tinh tế sẽ là gì?
sancho.s RebstateMonicaCellio


10

Nếu bạn đang tìm kiếm sự phản ánh của tất cả các thuộc tính, câu trả lời ở trên là tuyệt vời.

Nếu bạn chỉ đơn giản là tìm kiếm các khóa của từ điển (khác với 'đối tượng' trong Python), hãy sử dụng

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']

1
mặc dù đó là câu trả lời của tôi, tôi không nghĩ đó phải là câu trả lời được chấp nhận: các khóa của một đối tượng khác với thuộc tính của một thể hiện đối tượng của một lớp. Chúng được truy cập khác nhau ( obj['key']so với obj.property) và câu hỏi là về các thuộc tính đối tượng. Tôi đặt câu trả lời của mình ở đây vì có sự nhầm lẫn dễ dàng giữa hai người.
MrE

Tôi thực sự sẽ đề nghị loại bỏ câu trả lời này.
Nhập

Như đã nêu ở trên, những người đến từ Javascript hoặc C # chẳng hạn dễ bị nhầm lẫn bởi thuật ngữ này vì không có sự khác biệt giữa 2 khái niệm này. Những người học python và cố gắng truy cập các khóa rất có khả năng tìm kiếm 'thuộc tính' và kết thúc tại đây, do đó tôi nghĩ nó thuộc về nó.
MrE

và bạn đã đúng, nhưng bỏ lỡ vấn đề: trong các ngôn ngữ khác (lấy JS) không có sự phân biệt giữa đối tượng và từ điển. OP đến từ C # đặt câu hỏi. Câu trả lời này, mặc dù sai, có 11 câu trả lời, bằng chứng rằng những người hạ cánh ở đây thấy nó hữu ích, mặc dù về mặt kỹ thuật không phải là câu trả lời đúng (như tôi chỉ ra) cho câu hỏi khi nhìn vào nó trong biệt ngữ trăn nghiêm ngặt. Tôi sẽ chỉnh sửa để làm cho nó rõ ràng hơn nữa.
MrE

5

Điều này hoàn toàn được bao phủ bởi các câu trả lời khác, nhưng tôi sẽ làm cho nó rõ ràng. Một đối tượng có thể có các thuộc tính lớp và thuộc tính thể hiện tĩnh và động.

class foo:
    classy = 1
    @property
    def dyno(self):
        return 1
    def __init__(self):
        self.stasis = 2

    def fx(self):
        return 3

stasislà tĩnh, dynolà động (xem trang trí classythuộc tính ) và là một thuộc tính lớp. Nếu chúng ta chỉ đơn giản làm __dict__hoặc varschúng ta sẽ chỉ có được một tĩnh.

o = foo()
print(o.__dict__) #{'stasis': 2}
print(vars(o)) #{'stasis': 2}

Vì vậy, nếu chúng ta muốn những người khác __dict__sẽ nhận được mọi thứ (và nhiều hơn nữa). Điều này bao gồm các phương thức và thuộc tính ma thuật và các phương thức ràng buộc thông thường. Vì vậy, hãy tránh những điều đó:

d = {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}
print(d) #{'stasis': 2, 'classy': 1, 'dyno': 1}

Cuộc typegọi với một phương thức trang trí thuộc tính (một thuộc tính động) sẽ cung cấp cho bạn loại giá trị được trả về, không method. Để chứng minh điều này, hãy json xâu chuỗi nó:

import json
print(json.dumps(d)) #{"stasis": 2, "classy": 1, "dyno": 1}

Nếu nó là một phương pháp thì nó sẽ bị sập.

TL; DR. hãy thử gọi extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}cho cả ba, nhưng không phải phương pháp cũng không phải phép thuật.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.