จะทราบได้อย่างไรว่าวัตถุมีคุณสมบัติใน Python


1635

Python มีวิธีในการพิจารณาหรือไม่ว่าวัตถุมีคุณสมบัติบางอย่างหรือไม่? ตัวอย่างเช่น:

>>> 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'

คุณจะบอกaได้อย่างไรว่ามีแอตทริบิวต์propertyก่อนใช้งานหรือไม่

คำตอบ:


2340

ลองhasattr():

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

แก้ไข: ดูคำตอบของ zweiterlindeด้านล่างผู้เสนอคำแนะนำที่ดีเกี่ยวกับการขอการให้อภัย! วิธีการแบบ pythonic มาก!

การปฏิบัติทั่วไปในไพ ธ อนนั้นคือถ้าคุณสมบัติมีแนวโน้มที่จะมีเวลาส่วนใหญ่เพียงแค่เรียกมันและปล่อยให้ข้อยกเว้นแพร่กระจายหรือดักจับมันด้วยลอง / ยกเว้นบล็อก hasattrนี้อาจจะเร็วกว่า หากสถานที่ให้บริการมีแนวโน้มที่จะไม่มีเวลาส่วนใหญ่หรือคุณไม่แน่ใจการใช้hasattrอาจจะเร็วกว่าการอยู่ในบล็อกข้อยกเว้นซ้ำ ๆ


19
ดูเหมือนว่าจะทำงานเพื่อตรวจสอบฟังก์ชั่นในเนมสเปซเช่น: import string hasattr(string, "lower")
riviera

15
hasattrเหมือนกับการใช้try/ except AttributeError: docstring ของ hasattr (ใน Python 2.7) บอกว่ามันใช้ getattr hand catch ยกเว้น
Jeff Tratner

8
@JeffTratner: hasattrเป็นที่น่าเสียดายที่ไม่ตรงเช่นเดียวกับtry: ... except AttributeError:ในหลาม 2.x ตั้งแต่hasattrจะจับข้อยกเว้นทั้งหมด โปรดดูคำตอบของฉันสำหรับตัวอย่างและวิธีแก้ปัญหาง่ายๆ
Martin Geisler

1
@ MartinGeisler จุดดี - มันไม่เหมือนกับที่จับข้อยกเว้นทั้งหมด ไม่แน่ใจว่าเวอร์ชันใดที่ถูกต้องมากขึ้น - ขึ้นอยู่กับสมมติฐานที่คุณใช้และผู้ที่กำลังเรียกใช้ฟังก์ชันของคุณ ขอบคุณสำหรับการชี้แจง
Jeff Tratner

2
hasattrนอกจากนี้ยังเป็นตัวเลือกที่ดีกว่าหากคุณอยู่ในความเข้าใจเช่น[a.property for a in list_of_as if hasattr(a, "property")]
ราฟาเอลมาร์ติน

632

ดังที่Jarret Hardieตอบแล้วhasattrจะทำเคล็ดลับ ฉันอยากจะเพิ่มว่าหลาย ๆ คนในชุมชน Python แนะนำกลยุทธ์ "ง่ายต่อการขอการให้อภัยมากกว่าการอนุญาต" (EAFP) มากกว่า "มองก่อนที่คุณจะกระโดด" (LBYL) ดูข้อมูลอ้างอิงเหล่านี้:

EAFP เทียบกับ LBYL (Re: ผิดหวังเล็กน้อยจนถึงตอนนี้)
EAFP เทียบกับ LBYL @ รหัสเช่น Pythonista: Idiomatic Python

เช่น:

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

... ชอบที่จะ:

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

257
แต่คุณจะตรวจสอบได้อย่างไรว่าเป็น a.property ที่ทำให้เกิด AttributeError ไม่ใช่ใน doStuff () ดูเหมือนว่าคุณจะไม่ ฉันคิดว่ามันง่ายกว่าที่จะขอการให้อภัย แต่หลายครั้งก็ไม่ถูกต้องเช่นกัน
jpalecek

283
EAFP ดูเหมือนจะเป็นบ้า HasAttr โทรเลขไปยังโปรแกรมเมอร์ผู้ดูแลรักษาในอนาคตที่คุณกำลังตรวจสอบคุณลักษณะเฉพาะ การได้รับการยกเว้นจะไม่มีอะไรบอกโปรแกรมเมอร์ในอนาคตและอาจทำให้บางคนลงหลุมกระต่าย
Ethan Heilman

74
@ e5: คุณมีจุดยุติธรรมในกรณีนี้ แต่ในหลายกรณี EAFP เป็นตัวเลือกที่ถูกต้องเท่านั้น ตัวอย่างเช่นหากคุณตรวจสอบการมีอยู่ของไฟล์จากนั้นเปิดไฟล์โดยคาดว่าจะมีอยู่จริงรหัสของคุณไม่ถูกต้อง: ไฟล์อาจถูกลบหรือเปลี่ยนชื่อระหว่างการตรวจสอบและการใช้งาน สิ่งนี้เรียกว่าข้อผิดพลาด TOCTOU (เวลาในการตรวจสอบถึงเวลาใช้งาน) และนอกเหนือจากการทำให้เกิดข้อขัดข้องอาจเป็นแหล่งที่มาของช่องโหว่ความปลอดภัย
Max

15
@EthanHeilman เป็นบ้าเท่านั้นเมื่อมีความกำกวมในแหล่งที่มาของข้อยกเว้นซึ่งสามารถหลีกเลี่ยงได้ด้วยการออกแบบที่ดีในกรณีส่วนใหญ่ โครงสร้างที่มีเลเยอร์ที่ดีของตรรกะภายในลอง / ยกเว้น / ในที่สุดโดยทั่วไปจะทำให้ตรรกะ (ข้อผิดพลาดของโปรแกรมเมอร์มีแนวโน้มน้อยลง) ที่แข็งแกร่งกว่าการทิ้งโค้ดด้วยการทิ้งถ้าการตรวจสอบสำหรับรหัสการบริโภคแต่ละชิ้น ทำให้เกิดข้อผิดพลาดอย่างชัดเจนและช่วยให้ผู้ใช้โปรแกรมเมอร์มีตัวเลือกในการจัดการกับพวกเขาโดยตรง
ปีเตอร์เอ็มอีเลียส

64
ข้อร้องเรียนที่คลุมเครือส่วนใหญ่ที่นี่เป็นเพียงเพราะโค้ดตัวอย่างมีโครงสร้างไม่ดี สิ่งเดียวที่try:ควรทำคือการพยายามเข้าถึงแอตทริบิวต์ ไม่มีเหตุผลที่จะปิดการดำเนินการของdoStuffเช่นกัน ยังคงมีความเป็นไปได้บางอย่างสำหรับความกำกวมแม้ว่า: ถ้าpropertyเป็นคุณสมบัติที่คำนวณได้แทนแอตทริบิวต์ธรรมดาการใช้งานของมันสามารถยกระดับAttributeErrorภายใน นี่คือเหตุผลที่ในเกือบทุกสถานการณ์จริงเช่นนี้getattrเป็นที่นิยมอย่างใดอย่างหนึ่งหรือจับhasattr AttributeError
Carl Meyer

485

คุณสามารถใช้hasattr()หรือจับAttributeErrorแต่ถ้าคุณเพียงแค่ต้องการค่าของคุณลักษณะที่มีค่าเริ่มต้นถ้ามันไม่ได้มีตัวเลือกที่ดีที่สุดคือการใช้getattr():

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

14
สิ่งนี้จะช่วยแก้ปัญหาทั้งสองข้อข้างต้น: a) ความกำกวมของแหล่งที่มาของ AttributeError ที่เป็นไปได้ข) การรักษาแนวทาง EAFP
Peter M. Elias

6
มันก็เป็น 25% ของบรรทัดของโค้ด แน่นอนว่านี่จะต้องเป็นทางออกที่ดีที่สุด
fatuhoku

16
นี่เป็นทางออกที่ดีที่สุด "ถ้าคุณต้องการคุณค่าของแอตทริบิวต์ด้วยค่าเริ่มต้น" แม้ว่าฉันเชื่อว่านี่เป็นสิ่งที่หลายคนต้องการเมื่อพวกเขาบอกว่าพวกเขาต้องการตรวจสอบว่ามีแอตทริบิวต์อยู่หรือไม่ OP จริง ๆ ถามหลังดังนั้นจึงสมเหตุสมผลสำหรับคำตอบโดยตรงของคำถามนั้น (hasattr, AttributeError) ที่จะแสดงรายการที่สูงขึ้น .
Carl Meyer

41

ผมคิดว่าสิ่งที่คุณกำลังมองหาhasattr อย่างไรก็ตามฉันจะแนะนำสิ่งนี้ถ้าคุณต้องการตรวจสอบคุณสมบัติของหลาม -

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

ข้อเสียของที่นี่คือข้อผิดพลาดของแอ็ตทริบิวต์ใน__get__โค้ดคุณสมบัติจะถูกดักจับเช่นกัน

มิฉะนั้นทำ

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

เอกสาร: http://docs.python.org/library/functions.html
คำเตือน:
เหตุผลที่ฉันแนะนำคือ hasattr ตรวจไม่พบคุณสมบัติ
ลิงก์: http://mail.python.org/pipermail/python-dev/2005-December/058498.html


ดังนั้นคำแนะนำของคุณคือคุณไม่ต้องติดตั้ง - ใช้เลย!
SilentGhost

ไม่อย่างแน่นอนอย่าใช้ IFF ในตัวที่คุณต้องการตรวจจับคุณสมบัติ เป็นอย่างอื่น Hasattr เป็นสิ่งที่ดีอย่างสมบูรณ์
batbrat

3
hasattrตรวจจับคุณสมบัติโดยทั่วไปได้ดี เป็นเพียงการปฏิบัติต่อการเพิ่มข้อยกเว้นในpropertyฟังก์ชัน -wrapped ตามความหมายที่ไม่มีแอตทริบิวต์ดังกล่าวอยู่; โพสต์รายชื่อผู้รับจดหมาย Python ที่ลิงก์นั้นเป็นเรื่องของคุณสมบัติที่ทำให้เกิดข้อยกเว้นเมื่อคุณพยายามเข้าถึง สำหรับวัตถุประสงค์ในทางปฏิบัติแอตทริบิวต์ที่กล่าวว่าไม่มีอยู่เพราะจะไม่สร้างคุณค่า นอกจากนี้hasattrเฉพาะระงับข้อยกเว้นโดยทั่วไปใน Py 3.1 และรุ่นก่อนหน้า ใน 3.2+ ก็เพียงยับยั้ง (แทนที่ด้วยกลับ)False AttributeError
ShadowRanger

32

ตาม pydoc, hasattr (obj, prop) เพียงแค่เรียก getattr (obj, prop) และจับข้อยกเว้น ดังนั้นจึงเป็นเรื่องที่ถูกต้องเมื่อต้องการตัดการเข้าถึงแอ็ตทริบิวต์ด้วยคำสั่ง try และจับ AttributeError เนื่องจากใช้ Hasattr () ไว้ล่วงหน้า

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

2
Hasattr จริง ๆ แล้วอาจได้รับการปรับให้เหมาะสม เช่นกับ pypy
odinho - Velmont

6
+1 สิ่งนี้จะปลอดภัยยิ่งกว่าการใช้hasattrเมื่อการSomeClassแทนที่__getattr__นั้นhasattrจะดักจับข้อยกเว้นทั้งหมดใน Python 2.x ไม่AttributeErrorเหมือนกับที่คุณคาดหวัง สิ่งนี้ได้รับการแก้ไขใน Python 3.2 - โปรดดูคำตอบอื่น ๆ ของฉันสำหรับวิธีแก้ปัญหาง่ายๆ
Martin Geisler

24

ฉันขอแนะนำให้หลีกเลี่ยงสิ่งนี้:

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

ผู้ใช้ @jpalecek พูดถึงมัน: หากมีสิ่งใดAttributeErrorเกิดขึ้นภายในdoStuff()คุณกำลังหลงทาง

วิธีนี้อาจจะดีกว่า:

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

อาจเป็นเพียงแค่: try: a.propertyไม่จำเป็นต้องมีด้านซ้ายมือ
Petruza

จากนั้นคุณจะต้องทำซ้ำ a.property ในบล็อกอื่นและนั่นอาจล้มเหลว
Éric Araujo

13

ขึ้นอยู่กับสถานการณ์ที่คุณสามารถตรวจสอบกับisinstanceชนิดของวัตถุที่คุณมีแล้วใช้คุณลักษณะที่สอดคล้องกัน ด้วยการแนะนำคลาสพื้นฐานที่เป็นนามธรรมใน Python 2.6 / 3.0 วิธีการนี้ก็มีประสิทธิภาพมากกว่าเช่นกัน

สถานการณ์หนึ่งคือสิ่งนี้มีประโยชน์ถ้าวัตถุสองชนิดที่แตกต่างกันมีแอตทริบิวต์ที่มีชื่อเหมือนกัน แต่มีความหมายแตกต่างกัน การใช้เพียงอย่างเดียวhasattrอาจทำให้เกิดข้อผิดพลาดแปลก ๆ

ตัวอย่างที่ดีอย่างหนึ่งคือความแตกต่างระหว่างตัววนซ้ำและตัววนซ้ำ (ดูคำถามนี้ ) __iter__วิธีการใน iterator และ iterable มีชื่อเดียวกัน แต่จะมีความหมายที่แตกต่างกันมาก! ดังนั้นจึงhasattrไม่มีประโยชน์ แต่เมื่อisinstanceรวมกับ ABC's ก็เป็นวิธีที่สะอาด

อย่างไรก็ตามฉันยอมรับว่าในสถานการณ์ส่วนใหญ่hasattrวิธีการ (อธิบายไว้ในคำตอบอื่น ๆ ) เป็นทางออกที่เหมาะสมที่สุด


13

หวังว่าคุณจะคาดหวัง hasattr () แต่พยายามหลีกเลี่ยง hasattr () และโปรดเลือก getattr () getattr () เร็วกว่า Hasattr ()

ใช้ Hasattr ():

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

เหมือนกันที่นี่ฉันใช้ getattr เพื่อรับคุณสมบัติถ้าไม่มีคุณสมบัติมันส่งคืนไม่มี

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

11

แก้ไข : วิธีนี้มีข้อ จำกัด ร้ายแรง มันควรจะทำงานได้ถ้าวัตถุนั้นสามารถทำซ้ำได้ กรุณาตรวจสอบความคิดเห็นด้านล่าง

หากคุณใช้Python 3.6หรือสูงกว่าอย่างฉันมีทางเลือกที่สะดวกในการตรวจสอบว่าวัตถุมีคุณสมบัติเฉพาะหรือไม่:

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

อย่างไรก็ตามฉันไม่แน่ใจว่าวิธีใดดีที่สุดในตอนนี้ โดยใช้hasattr()การใช้หรือการใช้getattr() inความคิดเห็นยินดีต้อนรับ


6
inคำหลักทำงานได้สำหรับการตรวจสอบประเภท iterable ยกตัวอย่างเช่นโยนข้อผิดพลาด'foo' in None TypeError: argument of type 'NoneType' is not iterableการแก้ไขคือการตรวจสอบว่าเป็นชนิด iterable inก่อนที่จะใช้ หลังจากแก้ไขกรณีขอบเช่นประเภทที่ไม่สามารถทำซ้ำได้คุณน่าจะดีกว่าการใช้hasattr()เพราะมันถูกออกแบบมาเพื่อจัดการกับกรณีขอบ
Seth Difley

3
สิ่งนี้ไม่เกี่ยวกับการเข้าถึงคุณลักษณะ ฉันไม่รู้ว่ามันได้รับการสนับสนุนอย่างไร ความคล้ายคลึงกันเพียงอย่างเดียวที่มีในการเข้าถึงแอตทริบิวต์คือหากคุณใช้dictเป็น "วัตถุที่มีน้ำหนักเบา" ซึ่งคล้ายกับการออกแบบวัตถุ JavaScript แต่คลาสปกติส่วนใหญ่จะไม่รองรับสิ่งนี้โดยทั่วไป .
ShadowRanger

2
ถ้า 'ตัวแปร' ในคลาส. __ dict__: ??
Ben


1

นี่ง่ายมากเพียงแค่ใช้dir(อ็อบเจกต์)
นี่จะส่งคืนรายการของทุกฟังก์ชั่นที่มีอยู่และคุณสมบัติของวัตถุ


1

ตัวเลือกอื่นที่เป็นไปได้ แต่ขึ้นอยู่กับว่าคุณหมายถึงอะไรก่อนหน้านี้ :

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()

เอาท์พุท:

bar:1
zoom!

วิธีนี้ช่วยให้คุณสามารถตรวจสอบแอตทริบิวต์ที่ไม่มีค่าได้

แต่! ระวังให้มากคุณจะไม่ยกตัวอย่างและเปรียบเทียบundefinedสถานที่หลายแห่งโดยไม่ตั้งใจเพราะมันisจะไม่ทำงานในกรณีนั้น

ปรับปรุง:

เนื่องจากสิ่งที่ฉันถูกเตือนเกี่ยวกับในย่อหน้าข้างต้นมีหลาย undefineds ที่ไม่ตรงกันฉันเพิ่งปรับเปลี่ยนรูปแบบนี้เล็กน้อย:

undefined = NotImplemented

NotImplementedเพื่อไม่ให้สับสนกับNotImplementedErrorมันคือในตัว: มันตรงกับเจตนาของ JS undefinedและคุณสามารถนำความหมายกลับมาใช้ใหม่ได้ทุกที่และมันจะจับคู่เสมอ ข้อเสียคือมันเป็น "ความจริง" ใน booleans และสามารถดูแปลกในบันทึกและร่องรอยสแต็ค (แต่คุณได้อย่างรวดเร็วเมื่อคุณรู้ว่ามันปรากฏในบริบทนี้เท่านั้น)


0

คุณสามารถตรวจสอบว่าobjectมีคุณสมบัติโดยใช้hasattrวิธีการ builtin

เช่นถ้าวัตถุของคุณaและคุณต้องการตรวจสอบคุณลักษณะstuff

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

เมธอดลายเซ็นเองนั้นhasattr(object, name) -> boolหมายความว่าถ้าobjectมีแอททริบิวต์ซึ่งส่งผ่านไปยังอาร์กิวเมนต์ที่สองที่อยู่ในhasattrนั้นจะให้บูลีนTrueหรือFalseตามการปรากฏตัวของnameคุณลักษณะในวัตถุ


0

hasattr()เป็นคำตอบที่ถูก สิ่งที่ฉันต้องการเพิ่มคือhasattr()สามารถใช้ร่วมกับassert ได้ (เพื่อหลีกเลี่ยงifข้อความที่ไม่จำเป็นและทำให้โค้ดอ่านง่ายขึ้น):

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

ตามที่ระบุไว้ในคำตอบอื่นใน SO : การทดสอบควรใช้เพื่อทดสอบเงื่อนไขที่ไม่ควรเกิดขึ้น จุดประสงค์คือการหยุดทำงานเร็วในกรณีที่สถานะโปรแกรมเสียหาย


สิ่งนี้เป็นประโยชน์ แต่อาจไม่เป็นเช่นนั้นเสมอไป บางทีฉันต้องการทดสอบว่าวัตถุมีคุณสมบัติหรือไม่จากนั้นเพิ่มเป็นครั้งแรกหรืออาจต้องเรียกใช้รหัสอื่นสำหรับวัตถุที่มีคุณสมบัตินั้น เมื่อรหัสไม่สามารถดำเนินการต่อการยืนยันอาจถูกปรับ แต่ไม่เป็นเช่นนั้นเสมอไป สิ่งสำคัญคือการใช้งานhasattrไม่ได้รหัสรอบ
ลูคัสกาเบรียลซานเชซ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.