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


1635

Có cách nào trong Python để xác định xem một đối tượng có thuộc tính nào không? 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ể biết nếu acó thuộc tính propertytrước khi sử dụng nó?

Câu trả lời:


2343

Hãy thử hasattr():

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

EDIT: 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 pythonic!

Thực tiễn chung ở python là, nếu tài sản có khả năng ở đó hầu hết thời gian, chỉ cần gọi nó và để ngoại lệ lan truyền, hoặc bẫy nó bằng một khối thử / ngoại trừ. Đ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, việc sử dụng hasattrcó thể sẽ nhanh hơn nhiều lần rơi vào một khối ngoại lệ.


19
Có vẻ như cũng đang làm việc để kiểm tra các chức năng trong không gian tên, ví dụ: import string hasattr(string, "lower")
Riviera

15
hasattrhoàn toàn giống với việc sử dụng try/ except AttributeError: chuỗi docatt của hasattr (trong Python 2.7) nói rằng nó sử dụng hàm getattr bắt ngoại lệ.
Jeff Tratner

8
@JeffTratner: hasattrthật không may, không hoàn toàn giống như try: ... except AttributeError:trong Python 2.x vì hasattrsẽ bắt được 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

632

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

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

I E:

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

... được ưu tiên để:

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

258
Nhưng làm thế nào để bạn kiểm tra xem chính a.property đã gây ra AttributionError chứ không phải thứ gì đó trong doStuff ()? Có vẻ như bạn không. Tôi nghĩ rằng thực sự dễ dàng hơn để yêu cầu sự tha thứ, nhưng nhiều lần, nó cũng không chính xác.
jpalecek

285
EAFP dường như ... điên rồ. Điện báo HasAttr cho các lập trình viên bảo trì trong tương lai mà bạn đang kiểm tra một thuộc tính cụ thể. Nhận một ngoại lệ cho các lập trình viên tương lai không có gì và có thể dẫn ai đó xuống hố thỏ.
Ethan Heilman

74
@ 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 chính xác duy nhất. Ví dụ: nếu bạn kiểm tra sự tồn tại của tệp và sau đó mở tệp, hy vọng rằng nó chắc chắn sẽ tồn tại, mã của bạn không chính xác: tệp có thể bị xóa hoặc đổi tên giữa kiểm tra và sử dụng. Đâ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 của lỗ hổng bảo mật.
Tối đa

15
@EthanHeilman chỉ điên rồ khi có sự mơ hồ trong nguồn gốc của ngoại lệ, 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 logic được phân lớp tốt trong thử / ngoại trừ / cuối cùng thường làm cho logic mạnh mẽ hơn (ít xảy ra lỗi lập trình viên) hơn so với việc xả mã với các kiểm tra if ưu tiên cho 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 các lập trình viên tiêu thụ tùy chọn xử lý chúng trực tiếp.
Peter M. Elias

64
Hầu hết các khiếu nại mơ hồ ở đây chỉ đơn giản là vì mã mẫu có cấu trúc kém. Điều duy nhất bên trong try:nên là quyền truy cập thuộc tính đã thử; không có lý do để kết thúc việc thực hiện doStufflà tốt. Vẫn còn một số tiềm năng cho sự mơ hồ: nếu propertylà một thuộc tính được tính thay vì thuộc tính đơn giản, việc triển khai của nó có thể tăng lên AttributeErrortrong nội bộ. Đây là lý do tại sao trong hầu hết các tình huống thực tế như thế này, getattrtốt hơn là hasattrhoặc bắt AttributeError.
Carl Meyer

485

Bạn có thể sử 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 mặc định nếu nó không ở đó, thì tùy chọn tốt nhất chỉ là sử dụng getattr():

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

14
Điều này giải quyết cả hai vấn đề đã nói ở trên: a) Sự mơ hồ về nguồn gốc của một AttributionError có thể, b) Giữ nguyên cách tiếp cận EAFP.
Peter M. Elias

6
Đó cũng là 25% dòng mã. Chắc chắn đây phải là giải pháp tốt nhất.
fatuhoku

16
Đâ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 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 có thuộc tính nào hay không, nhưng OP thực sự đã hỏi cái sau, vì vậy thật hợp lý khi câu trả lời trực tiếp cho câu hỏi đó (hasattr, AttributionError) được liệt kê cao hơn .
Carl Meyer

41

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

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

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

Nếu không, làm-

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

Tài liệu: http://docs.python.org/l Library / fifts.html
Cảnh báo:
Lý do cho khuyến nghị 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


3
hasattrphát hiện tài sản nói chung chỉ tốt. Chỉ là nó xử lý việc đưa ra một ngoại lệ trong propertyhàm bị loại bỏ vì có nghĩa là không có thuộc tính nào như vậy tồn tại; bài đăng danh sách gửi thư Python được liên kết là về một thuộc tính làm tăng ngoại lệ khi bạn cố gắng truy cập nó. Đối với tất cả các mục đích thực tế, thuộc tính cho biết không tồn tại, bởi vì nó sẽ không bao giờ tạo ra một giá trị. Ngoài ra, hasattrchỉ loại bỏ các ngoại lệ nói chung trên Py 3.1 trở về trước; trong 3.2+, nó chỉ triệt tiêu (thay thế bằng Falsetrả về) AttributeError.
ShadowRanger

32

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

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

2
Vâng hasattr thực sự có thể được tối ưu hóa. Ví dụ với pypy.
odinho - Velmont

6
+1. Điều này thậm chí còn an toàn hơn so với việc sử dụng hasattrkhi SomeClassghi đè __getattr__hasattrsẽ nắm bắt tất cả các ngoại lệ trong Python 2.x, không AttributeErrorgiống 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 cách giải quyết đơn giản.
Martin Geisler

24

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 AttributeErrorxảy ra bên trongdoStuff() , bạn sẽ bị mất.

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

Tùy thuộc vào tình huống bạn có thể kiểm tra với isinstanceloạ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 các 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 cách gõ vịt tinh vi hơn).

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

Một ví dụ điển hình là sự phân biệt giữa các trình vòng lặp và các vòng lặp (xem câu hỏi này ). Các __iter__phương thức trong một iterator và một iterable có cùng tên nhưng khác nhau về mặt ngữ nghĩa! Như vậy hasattrlà vô ích, nhưng isinstancecù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 tình huống, hasattrcách tiếp cận (được mô tả trong các câu trả lời khác) là giải pháp phù hợp nhất.


13

Hy vọng bạn mong đợi hasattr (), nhưng cố gắng tránh hasattr () và vui lòng thích getattr (). getattr () nhanh hơn hasattr ()

sử dụng hasattr ():

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

tương tự ở đây tôi đang sử dụng getattr để lấy tài sản nếu không có tài sản thì nó không trả lại

   property = getattr(a,"property",None)
    if property:
        print property

11

EDIT : Cách tiếp cận này có giới hạn nghiêm trọng. Nó sẽ hoạt động nếu đối tượng là một lần lặp . Vui lòng kiểm tra các ý kiến ​​dưới đây.

Nếu bạn đang sử dụng Python 3.6 trở lên như tôi, có một cách thay thế thuận tiện để kiểm tra xem một đối tượng có thuộc tính cụ thể không:

if 'attr1' in obj1:
    print("attr1 = {}".format(obj1["attr1"]))

Tuy nhiên, tôi không chắc đó là cách tiếp cận tốt nhất ngay bây giờ. sử dụng hasattr(), sử dụng getattr()hoặc sử dụng in. Bình luận được chào đón.


6
intừ khóa hoạt động để kiểm tra các loại lặp. Ví dụ, 'foo' in Noneném lỗi TypeError: argument of type 'NoneType' is not iterable. Cách khắc phục là kiểm tra xem loại có thể lặp lại trước khi sử dụng không in. Sau khi sửa lỗi cho các trường hợp cạnh như loại không thể lặp lại, có lẽ bạn nên sử dụng hasattr()vì nó được thiết kế để xử lý các trường hợp cạnh.
Seth Difley

3
Điều này không có gì để làm với quyền truy cập thuộc tính. Tôi không biết làm thế nào nó được nâng cấp. Điểm giống nhau duy nhất mà nó có thuộc tính truy cập là nếu bạn đang sử dụng dictnhư một "đối tượng nhẹ", tương tự như thiết kế của các đối tượng JavaScript, nhưng hầu hết các lớp bình thường sẽ không hỗ trợ điều này nói chung (nhận một biến thể về lỗi được đề cập bởi @SethDifley) .
ShadowRanger

6

Đây là một cách tiếp cận rất trực quan:

if 'property' in dir(a):
    a.property

1

Điều này là siêu đơn giản, chỉ cần sử dụng dir(đối tượng)
Điều này sẽ trả về một danh sách của tất cả các chức năng và thuộc tính có sẵn của đối tượng.


1

Một tùy chọn khác có thể, nhưng nó phụ thuộc vào ý của bạn trước đây :

undefined = object()

class Widget:

    def __init__(self):
        self.bar = 1

    def zoom(self):
        print("zoom!")

a = Widget()

bar = getattr(a, "bar", undefined)
if bar is not undefined:
    print("bar:%s" % (bar))

foo = getattr(a, "foo", undefined)
if foo is not undefined:
    print("foo:%s" % (foo))

zoom = getattr(a, "zoom", undefined)
if zoom is not undefined:
    zoom()

đầu ra:

bar:1
zoom!

Điều này cho phép bạn thậm chí kiểm tra các thuộc tính Không có giá trị.

Nhưng! Hãy cẩn thận, bạn không vô tình khởi tạo và so sánh undefinednhiều nơi vì issẽ không bao giờ hoạt động trong trường hợp đó.

Cập nhật:

bởi vì những gì tôi đã cảnh báo trong đoạn văn trên, có nhiều định nghĩa không bao giờ khớp, tôi gần đây đã sửa đổi một chút mô hình này:

undefined = NotImplemented

NotImplemented, đừng nhầm lẫn NotImplementedError, là một tích hợp: nó phù hợp với ý định của một JS undefinedvà bạn có thể sử dụng lại định nghĩa của nó ở mọi nơi và nó sẽ luôn khớp. Hạn chế là nó "trung thực" trong booleans và nó có thể trông kỳ lạ trong các bản ghi và dấu vết ngăn xếp (nhưng bạn nhanh chóng vượt qua nó khi bạn biết nó chỉ xuất hiện trong bối cảnh này).


0

Bạn có thể kiểm tra xem objectcó chứa thuộc tính hay không bằng cách sử dụng hasattrphương thức dựng sẵn.

Ví dụ nếu đối tượng của bạn là avà bạn muốn kiểm tra thuộc tínhstuff

>>> class a:
...     stuff = "something"
... 
>>> hasattr(a,'stuff')
True
>>> hasattr(a,'other_stuff')
False

Bản thân chữ ký phương thức hasattr(object, name) -> boolcó nghĩa là nếu objectthuộc tính được truyền cho đối số thứ hai hasattrhơn là mang lại boolean Truehoặc Falsetheo sự hiện diện của namethuộc tính trong đối tượng.


0

hasattr()là câu trả lời đúng Điều tôi muốn thêm là hasattr()cũng có thể được sử dụng tốt cùng với khẳng định (để tránh các ifcâu lệnh không cần thiết và làm cho mã dễ đọc hơn):

assert hasattr(a, 'property'), 'object lacks property' 

Như đã nêu trong một câu trả lời khác về SO : Assts nên được sử dụng để kiểm tra các điều kiện không bao giờ xảy ra. Mục đích là để sụp đổ sớm trong trường hợp trạng thái chương trình bị hỏng.


Điều này rất hữu ích nhưng có thể không phải luôn luôn như vậy. Có lẽ tôi muốn kiểm tra xem đối tượng có thuộc tính không và sau đó thêm nó lần đầu tiên hoặc có thể tôi phải chạy mã khác nhau cho các đối tượng có thuộc tính đó. Khi mã không thể tiếp tục, khẳng định có thể ổn. Nhưng một lần nữa, không phải lúc nào cũng như vậy. Điều quan trọng là việc sử dụng hasattrkhông phải mã xung quanh.
Lucas Gabriel Sánchez
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.