Câu hỏi Làm thế nào để biết nếu một đối tượng có một thuộc tính trong Python


Có cách nào trong Python để xác định nếu một đối tượng có một số thuộc tính? Ví dụ:

>>> a = SomeClass()
>>> a.someProperty = value
>>> a.property
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass instance has no attribute 'property'

Làm thế nào bạn có thể nói nếu a có thuộc tính property trước khi sử dụng nó?


1143
2018-03-04 14:45


gốc




Các câu trả lời:


Thử hasattr():

if hasattr(a, 'property'):
    a.property

CHỈNH SỬA: Xem câu trả lời của zweiterlinde dưới đây, người đưa ra lời khuyên tốt về việc yêu cầu sự tha thứ! Một cách tiếp cận rất nhiệt tình!

Thực hành chung trong python là, nếu thuộc tính có khả năng ở đó hầu hết thời gian, chỉ cần gọi nó và cho phép ngoại lệ lan truyền, hoặc bẫy nó với một khối try / except. Điều này có thể sẽ nhanh hơn hasattr. Nếu tài sản có khả năng không ở đó hầu hết thời gian, hoặc bạn không chắc chắn, bằng cách sử dụng hasattr có thể sẽ nhanh hơn nhiều lần rơi vào một khối ngoại lệ.


1599
2018-03-04 14:48



Dường như cũng đang làm việc để kiểm tra các hàm trong không gian tên, ví dụ: import string hasattr(string, "lower") - riviera
hasattr chính xác giống như sử dụng try/except AttributeError: docstring của hasattr (trong Python 2.7) nói rằng nó sử dụng getattr hand catches exception. - Jeff Tratner
Tôi nghĩ rằng trường hợp sử dụng rõ ràng nhất không có gì liên quan đến sự tha thứ và là "khởi tạo nó nếu nó không có" cho việc khởi tạo lười biếng. Đồng vị trí khởi tạo và sử dụng trong nguồn thường tốt hơn so với khởi tạo ở một nơi và sử dụng ở nơi khác. - Evgeni Sergeev
@JeffTratner: hasattr thật không may là không chính xác giống như một try: ... except AttributeError: trong Python 2.x kể từ hasattr sẽ bắt tất cả ngoại lệ. Xin vui lòng xem câu trả lời của tôi cho một ví dụ và một cách giải quyết đơn giản. - Martin Geisler
@MartinGeisler Tốt điểm - nó không giống như nó bắt tất cả các trường hợp ngoại lệ. Không chắc chắn phiên bản nào chính xác hơn - thực sự phụ thuộc vào các giả định bạn đang làm việc và ai đang gọi chức năng của bạn. Cảm ơn bạn đã làm rõ. - Jeff Tratner


Như Jarret Hardie trả lời, hasattr sẽ làm các trick. Tuy nhiên, tôi muốn nói thêm rằng nhiều người trong cộng đồng Python đề xuất một chiến lược "dễ yêu cầu sự tha thứ hơn sự cho phép" (EAFP) hơn là "nhìn trước khi bạn nhảy" (LBYL). Xem các tài liệu tham khảo sau:

EAFP vs LBYL (là Re: Một chút thất vọng cho đến nay)
EAFP so với LBYL @Code Giống như Pythonista: Python độc đáo

I E:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

... được ưa thích hơn:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()

463
2018-03-04 14:56



Nhưng làm thế nào để bạn kiểm tra xem nó là a.property gây ra AttributeError, và không phải cái gì trong doStuff ()? Có vẻ như bạn không. Tôi nghĩ việc yêu cầu tha thứ thực sự dễ dàng hơn, nhưng nhiều lần, nó cũng không chính xác. - jpalecek
EAFP có vẻ ... điên rồ. HasAttr điện báo để lập trình bảo trì trong tương lai mà bạn đang kiểm tra cho một thuộc tính cụ thể. Nhận được một ngoại lệ cho các lập trình viên trong tương lai không có gì và có thể dẫn ai đó xuống hố thỏ. - Ethan Heilman
@ e5: bạn có một điểm công bằng trong trường hợp này, nhưng trong nhiều trường hợp EAFP là lựa chọn duy nhất đúng. Ví dụ, nếu bạn kiểm tra sự tồn tại của một tập tin và sau đó mở nó, hy vọng rằng nó chắc chắn sẽ tồn tại, mã của bạn là không chính xác: các tập tin có thể bị xóa hoặc đổi tên giữa kiểm tra và sử dụng. Điều này được gọi là lỗi TOCTOU (Thời gian kiểm tra thời gian sử dụng) và bên cạnh việc gây ra sự cố cũng có thể là một nguồn lỗ hổng bảo mật. - Max
@EthanHeilman nó chỉ điên rồ khi có sự mơ hồ trong nguồn gốc của ngoại lệ, mà có thể tránh được với thiết kế tốt trong hầu hết các trường hợp. Cấu trúc phân lớp tốt của logic trong thử / ngoại trừ / cuối cùng thường làm cho logic dễ bị lỗi (lập trình ít dễ bị lỗi) logic hơn việc xả rác mã bằng cách kiểm tra trước nếu kiểm tra từng đoạn mã tiêu thụ. Làm cho các lỗi cũng rất rõ ràng và cho phép người lập trình tiêu thụ tùy chọn giao dịch trực tiếp với họ. - Peter M. Elias
Hầu hết các khiếu nại về sự mơ hồ ở đây đơn giản chỉ vì mã mẫu được cấu trúc kém. Điều duy nhất bên trong try: nên là truy cập thuộc tính đã cố gắng; không có lý do gì để thực hiện doStuff cũng. Vẫn còn một số tiềm năng cho sự mơ hồ mặc dù: nếu propertylà một thuộc tính được tính thay vì một thuộc tính đơn giản, việc thực thi nó có thể tăng AttributeError trong nội bộ. Đây là lý do tại sao trong hầu như tất cả các tình huống thực tế như thế này, getattr thích hợp hơn hoặc là hasattr hoặc bắt AttributeError. - Carl Meyer


Bạn có thể dùng hasattr() hoặc bắt AttributeError, nhưng nếu bạn thực sự chỉ muốn giá trị của thuộc tính với giá trị mặc định nếu thuộc tính đó không có, tùy chọn tốt nhất chỉ là sử dụng getattr():

getattr(a, 'property', 'default value')

371
2018-03-04 17:54



Điều này giải quyết cả hai vấn đề nói trên: a) Sự mơ hồ của nguồn của một AttributeError có thể, b) Bảo tồn phương pháp tiếp cận EAFP. - Peter M. Elias
Nó cũng là 25% của các dòng mã. Chắc chắn đây phải là giải pháp tốt nhất. - fatuhoku
Đây là giải pháp tốt nhất "nếu bạn thực sự chỉ muốn giá trị của thuộc tính với giá trị mặc định". Mặc dù tôi tin rằng đây là điều mà nhiều người thực sự muốn khi họ nói rằng họ muốn phát hiện xem một thuộc tính có hiện diện hay không, OP thực sự yêu cầu điều này, vì vậy nó hợp lý cho các câu trả lời trực tiếp cho câu hỏi đó (hasattr, AttributeError) . - Carl Meyer
Nhưng hynek.me/articles/hasattr - AlxVallejo


Tôi nghĩ những gì bạn đang tìm kiếm là hasattr. Tuy nhiên, tôi muốn giới thiệu một cái gì đó như thế này nếu bạn muốn phát hiện thuộc tính python- -

try:
    getattr(someObject, 'someProperty')         
except AttributeError:
    print "Doesn't exist"
else
    print "Exists"

Điểm bất lợi ở đây là các lỗi thuộc tính trong các thuộc tính __get__ mã cũng bị bắt.

Nếu không, hãy làm

if hasattr(someObject, 'someProp'):
    #Access someProp/ set someProp
    pass

Tài liệu:http://docs.python.org/library/functions.html
Cảnh báo:
Lý do cho đề xuất của tôi là hasattr không phát hiện thuộc tính.
Liên kết:http://mail.python.org/pipermail/python-dev/2005-December/058498.html


33
2018-03-04 14:52



vì vậy, lời khuyên của bạn không phải là bạn buil-in - thực hiện nó! - SilentGhost
Vâng, không chính xác, không sử dụng IFF tích hợp mà bạn muốn phát hiện các thuộc tính. Nếu không hasattr là hoàn toàn tốt. - batbrat
hasattr phát hiện các thuộc tính nói chung tốt. Nó chỉ là nó xử lý một ngoại lệ trong propertychức năng -wrapped như ý nghĩa không có thuộc tính như vậy tồn tại; bài đăng danh sách gửi thư được liên kết với Python là về một thuộc tính làm tăng ngoại lệ khi bạn cố truy cập nó. Đối với tất cả các mục đích thực tế, thuộc tính nói không tồn tại, bởi vì nó sẽ không bao giờ tạo ra một giá trị. Cũng thế, hasattr chỉ ngăn chặn ngoại lệ nói chung trên Py 3.1 và trước đó; trong 3.2+, nó chỉ ngăn chặn (thay thế bằng False trở về) AttributeError. - ShadowRanger


Theo pydoc, hasattr (obj, prop) đơn giản gọi getattr (obj, prop) và bắt ngoại lệ. Vì vậy, nó chỉ là hợp lệ để bọc truy cập thuộc tính với một câu lệnh try và bắt AttributeError vì nó sử dụng hasattr () trước đó.

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value

24
2018-03-04 14:56



Vâng hasattr thực sự có lẽ được tối ưu hóa. Ví dụ. với pypy. - odinho - Velmont
+1. Điều này thậm chí là an toàn hơn hơn là sử dụng hasattr khi nào SomeClass ghi đè __getattr__ kể từ đó hasattr Sẽ bắt tất cả các ngoại lệ trong Python 2.x, không chỉ AttributeError như bạn mong đợi. Điều này đã được sửa trong Python 3.2 - vui lòng xem câu trả lời khác của tôi cho một giải pháp đơn giản. - Martin Geisler


Tôi muốn đề nghị tránh điều này:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

Người dùng @jpalecek đã đề cập đến nó: Nếu một AttributeError xảy ra bên trong doStuff(), bạn bị lạc.

Có lẽ cách tiếp cận này là tốt hơn:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)

13
2017-08-26 13:04





Tùy thuộc vào tình huống bạn có thể kiểm tra isinstance loại đối tượng bạn có, và sau đó sử dụng các thuộc tính tương ứng. Với sự ra đời của lớp cơ sở trừu tượng trong Python 2.6 / 3.0, cách tiếp cận này cũng trở nên mạnh mẽ hơn nhiều (về cơ bản ABC cho phép gõ một cách tinh vi hơn).

Một tình huống là điều này rất hữu ích nếu hai đối tượng khác nhau có thuộc tính có cùng tên, nhưng với ý nghĩa khác. Chỉ sử dụng hasattr sau đó có thể dẫn đến các lỗi lạ.

Một ví dụ điển hình là sự khác biệt giữa các trình vòng lặp và vòng lặp (xem điều này câu hỏi). Các __iter__ các phương thức trong một iterator và một iterable có cùng tên nhưng có ngữ nghĩa khá khác nhau! Vì thế hasattr là vô dụng, nhưng isinstance cùng với ABC cung cấp một giải pháp sạch.

Tuy nhiên, tôi đồng ý rằng trong hầu hết các trường hợp, hasattr cách tiếp cận (được mô tả trong các câu trả lời khác) là giải pháp thích hợp nhất.


11
2018-03-04 15:41