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


133

IC # เราทำผ่านการไตร่ตรอง ใน Javascript นั้นง่ายมาก:

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

วิธีทำใน Python



3
โปรดทราบว่าคำถามนี้เป็นการเรียกชื่อผิด คำตอบส่วนใหญ่จะเกี่ยวกับการแจงสมาชิก ผมกำลังมองหาวิธีที่จะระบุคุณสมบัติ@propertyสมาชิกเช่นของชั้นตกแต่งด้วย
Tomasz Gandor

คำตอบ:


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

โปรดทราบว่าในบางกรณีมีคุณสมบัติชั้นเรียนดังกล่าวมักจะไม่มี__slots____dict__


1
ตอนนี้จะเปลี่ยนค่าอย่างไร? ใน Javascript คุณสามารถทำได้: object [property] = newValue วิธีทำใน Python
Jader Dias

39
ใช้ setattr () แทน
Nelson

1
@ เนลสันคุณช่วยอธิบายได้ไหมว่าทำไมถึงเป็นตัวเลือกที่ดีกว่า สั้นกว่าหรือมีข้อควรพิจารณาเพิ่มเติมหรือไม่?
WhyNotHugo

8
@Hugo: อันดับแรกเพราะมันเป็น "pythonic" กล่าวอีกนัยหนึ่งนั่นคือไวยากรณ์ที่ชุมชนส่วนใหญ่คาดหวังว่าจะได้เห็น ไวยากรณ์อื่น ๆ มีแนวโน้มที่จะให้ทุกคนที่อ่านโค้ดของคุณหยุดโดยไม่จำเป็น __setattr__()ประการที่สองบางชนิดใช้หมา การตั้งค่าโดยตรงบนพจนานุกรมจะข้ามตัวตั้งค่าของวัตถุ (และ / หรือผู้ปกครอง) เป็นเรื่องปกติธรรมดาใน python ที่มีสิ่งต่างๆมากกว่าที่ตาเห็นเกิดขึ้นในพื้นหลังระหว่างการตั้งค่าแอตทริบิวต์ (เช่นการสุขาภิบาล) การใช้setattr()เพื่อให้แน่ใจว่าคุณจะไม่พลาดหรือถูกบังคับให้จัดการด้วยตนเองอย่างชัดเจน
Michael Ekoka

3
@ Hi-แองเจิลที่ไม่ทำงาน อย่างไรก็ตามสิ่งที่ไม่ได้ผลคือกลุ่มดาวของความคิดล่วงหน้าและสมมติฐานที่คุณมีสถานะโดยรอบเทียบกับสมาชิกวัตถุแบบไดนามิกใน Python vars()ส่งคืนเฉพาะสมาชิกแบบคงที่ (กล่าวคือแอตทริบิวต์ของอ็อบเจ็กต์และเมธอดที่ลงทะเบียนกับอ็อบเจ็กต์นั้น__dict__) มันไม่ส่งคืนสมาชิกไดนามิก (เช่นคุณสมบัติของวัตถุและวิธีการที่กำหนดแบบไดนามิกโดย__getattr__()วิธีการของวัตถุนั้นหรือเวทมนตร์ที่คล้ายกัน) ในโอกาสทั้งหมดที่คุณต้องการfile.ImplementationNameคุณสมบัติที่มีการกำหนดแบบไดนามิกและด้วยเหตุนี้ไม่สามารถใช้ได้กับหรือvars() dir()
Cecil Curry

69

ดูinspect.getmembers(object[, predicate]).

ส่งคืนสมาชิกทั้งหมดของออบเจ็กต์ในรายการคู่ (ชื่อค่า) ที่เรียงตามชื่อ หากมีการระบุอาร์กิวเมนต์เพรดิเคตที่เป็นทางเลือกจะมีเฉพาะสมาชิกที่เพรดิเคตส่งคืนค่าจริงเท่านั้น

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

ใช่คำตอบนี้ดีมาก ไม่เคยใช้โมดูลนี้มาก่อน getmembers () ถูกนำมาใช้โดยเพียงแค่เดินผลลัพธ์ของ dir (object), btw
Nelson

คุณสามารถอธิบายได้อย่างละเอียดว่าทำไมถึงดีกว่าการเข้าถึงdict ? เอกสาร Python มีประโยชน์น้อยกว่าโดยเฉพาะอย่างยิ่งเนื่องจากโดยปกติจะใช้คำนี้attributesแทนmembers(มีความแตกต่างระหว่างสองหรือไม่) พวกเขาสามารถแก้ไขชื่อใน Python 3.0 เพื่อให้สอดคล้องกัน
nikow

อ๊ะหมายถึง__dict__ขอโทษ
nikow

4
@nikow: Inspector.getmembers () รับประกันว่าจะทำงานต่อไปแม้ว่ารายละเอียดภายในจะเปลี่ยนไปก็ตาม
Georg Schölly

3
@NicholasKnight inspect.getmembers()ตัดdir()กับ (เล็กน้อยส่วนใหญ่) ผลประโยชน์ด้านข้างของ(A)รวมทั้งคุณลักษณะระดับแบบไดนามิกและคุณลักษณะ metaclassและ(ข)ไม่รวมสมาชิกไม่ตรงกับคำกริยาผ่าน หาวใช่ไหม? inspect.getmembers()เหมาะสำหรับไลบรารีของบุคคลที่สามโดยทั่วไปที่สนับสนุนประเภทอ็อบเจ็กต์ที่เป็นไปได้ทั้งหมด อย่างไรก็ตามสำหรับกรณีการใช้งานมาตรฐานก็dir()เพียงพอแล้ว
Cecil Curry

66

dir()เป็นวิธีง่ายๆ ดูที่นี่:

คำแนะนำเกี่ยวกับ Python Introspection


2
สิ่งที่ควรทราบจากเอกสาร Python เนื่องจาก dir () จัดทำขึ้นเพื่อความสะดวกในการใช้งานที่พรอมต์แบบโต้ตอบเป็นหลักจึงพยายามจัดหาชุดชื่อที่น่าสนใจมากกว่าที่จะพยายามจัดหาชุดชื่อที่กำหนดอย่างเข้มงวดหรือสม่ำเสมอและ พฤติกรรมโดยละเอียดอาจเปลี่ยนแปลงไปในทุกรุ่น ตัวอย่างเช่นแอตทริบิวต์ metaclass ไม่อยู่ในรายการผลลัพธ์เมื่ออาร์กิวเมนต์เป็นคลาส
skyler

1
คำตอบนี้ดีที่สุดเมื่อทำการขูดบน cli

15 ปีของหลาม (ไม่ใช่งานประจำ) และฉันยังลืมdir()ขอบคุณ
Abhishek Dujari

14

__dict__คุณสมบัติของวัตถุที่เป็นพจนานุกรมของคุณสมบัติอื่น ๆ ทั้งหมดที่กำหนดไว้ โปรดทราบว่าการเรียนหลามสามารถแทนที่getattr และทำให้สิ่งที่มีลักษณะเหมือนคุณสมบัติ __dict__แต่ไม่ได้อยู่ใน นอกจากนี้ยังมีฟังก์ชั่นในตัวvars()และdir()ที่มีความแตกต่างกันในรูปแบบที่ลึกซึ้ง และ__slots__สามารถแทนที่__dict__ในคลาสที่ผิดปกติบางอย่าง

วัตถุมีความซับซ้อนใน Python __dict__เป็นจุดเริ่มต้นที่เหมาะสมสำหรับการเขียนโปรแกรมแบบสะท้อนแสง dir()เป็นจุดเริ่มต้นหากคุณกำลังแฮ็กข้อมูลในเชลล์แบบโต้ตอบ


print vars.__doc__บ่งชี้ว่าWith an argument, equivalent to object.__dict__แล้วความแตกต่างที่ลึกซึ้งจะเป็นอย่างไร?
sancho.s ReinstateMonicaCellio


10

หากคุณกำลังมองหาการสะท้อนของคุณสมบัติทั้งหมดคำตอบข้างต้นนั้นดีมาก

หากคุณต้องการรับคีย์ของพจนานุกรม (ซึ่งแตกต่างจาก 'object' ใน Python) ให้ใช้

my_dict.keys()

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

1
แม้ว่าจะเป็นคำตอบของฉัน แต่ฉันไม่คิดว่ามันควรจะเป็นคำตอบที่ยอมรับ: คีย์ของอ็อบเจกต์นั้นแตกต่างจากคุณสมบัติของอินสแตนซ์อ็อบเจ็กต์ของคลาส เข้าถึงได้แตกต่างกัน ( obj['key']เทียบกับobj.property) และคำถามเกี่ยวกับคุณสมบัติของวัตถุ ฉันใส่คำตอบไว้ที่นี่เพราะทั้งสองมีความสับสนได้ง่าย
MrE

ฉันขอแนะนำให้ลบคำตอบนี้ออก
Ente

ตามที่ระบุไว้ข้างต้นตัวอย่างเช่นผู้ที่มาจาก Javascript หรือ C # จะสับสนกับคำศัพท์ได้ง่ายเนื่องจาก 2 แนวคิดนี้ไม่มีความแตกต่างกัน คนที่เรียนรู้ python และพยายามเข้าถึงคีย์มักจะค้นหา 'คุณสมบัติ' และจบลงที่นี่ด้วยเหตุนี้ฉันจึงคิดว่ามันเป็น
MrE

และคุณพูดถูก แต่พลาดประเด็น: ในภาษาอื่น (ใช้ JS) ไม่มีความแตกต่างระหว่างอ็อบเจ็กต์และพจนานุกรม OP มาจาก C # ถามคำถาม คำตอบนี้แม้ว่าจะผิด แต่ก็ได้รับการโหวต 11 ครั้งซึ่งพิสูจน์ได้ว่าผู้คนที่มาที่นี่พบว่ามีประโยชน์แม้ว่าจะไม่ใช่คำตอบที่ถูกต้องในทางเทคนิค (ตามที่ฉันชี้ให้เห็น) สำหรับคำถามเมื่อดูด้วยศัพท์แสงหลามที่เข้มงวด ฉันจะแก้ไขเพื่อให้ชัดเจนยิ่งขึ้น
MrE

5

คำตอบอื่น ๆ ครอบคลุมทั้งหมดนี้ แต่ฉันจะทำให้ชัดเจน อ็อบเจ็กต์อาจมีคลาสแอ็ตทริบิวต์และแอ็ตทริบิวต์อินสแตนซ์แบบคงที่และไดนามิก

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

    def fx(self):
        return 3

stasisเป็นแบบคงที่dynoเป็นไดนามิก (ตัวตกแต่งคุณสมบัติ cf. ) และclassyเป็นแอตทริบิวต์คลาส ถ้าเราทำเฉยๆ__dict__หรือvarsเราจะได้ค่าคงที่เท่านั้น

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

ดังนั้นหากเราต้องการให้คนอื่น__dict__ได้รับทุกอย่าง (และอื่น ๆ ) ซึ่งรวมถึงวิธีการและคุณสมบัติทางเวทมนตร์และวิธีการผูกแบบปกติ ดังนั้นให้หลีกเลี่ยงสิ่งเหล่านี้:

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}

typeเรียกว่ามีวิธีการตกแต่งสถานที่ให้บริการ (แอตทริบิวต์แบบไดนามิก) methodจะทำให้คุณชนิดของค่ากลับมาไม่ได้ เพื่อพิสูจน์สิ่งนี้ให้ json กำหนดมัน:

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

ถ้ามันเป็นวิธีการที่มันจะล้มเหลว

TL; DR ลองเรียกextravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}ทั้งสาม แต่ไม่ใช่วิธีการหรือเวทมนตร์

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