Як перерахувати властивості об'єкта в Python?


133

IC # ми робимо це через рефлексію. У Javascript це просто так:

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

Як це зробити в Python?



3
Зверніть увагу, що це питання є помилковим. Більшість відповідей стосується перерахування членів . Я шукав спосіб перерахувати властивості , тобто членів класу, прикрашених @property.
Томаш

Відповіді:


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

Майте на увазі, що в деяких рідкісних випадках є __slots__властивість, таких класів часто немає __dict__.


1
тепер як змінити значення? у Javascript ви можете зробити: object [property] = newValue. Як це зробити в Python?
Jader Dias

39
використовуйте натомість setattr ().
Нельсон

1
@Nelson Не могли б ви пояснити, чому це кращий варіант? Це просто коротше, чи є додаткові міркування?
WhyNotHugo

8
@Hugo: По-перше, це "пітонічне", іншими словами, це синтаксис, який очікує бачити більшість громади. Інший синтаксис, ймовірно, зайвим буде робити паузу для кожного, хто читає ваш код. По-друге, деякі типи реалізують сетер __setattr__(). Встановлення значень безпосередньо у словнику обходить установку об'єкта (та / або його батьків). У python досить часто зустрічається, що більше речей, ніж очі, відбувається у фоновому режимі під час налаштування атрибутів (наприклад, санітарія), використовуючи setattr()гарантування того, що ви не пропустите або змушені самі явно їх обробляти.
Майкл Екока

3
@ Hi-Angel Це робить роботу. Однак це не працює, - це сузір'я попередніх уявлень і припущень, що у вас є оточуючий статус, порівняно з динамічними членами об’єкта в Python. vars()повертає лише статичні члени (тобто атрибути об'єктів та методи, зареєстровані разом з об'єктами __dict__). Він не повертає динамічних членів (тобто атрибутів об'єктів та методів, динамічно визначених методом цього об'єкта __getattr__()чи подібною магією). Ймовірно, ваше бажане file.ImplementationNameвластивість визначається динамічно і, отже, не доступне для vars()або dir().
Сесіль Карі

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.
Нельсон

Чи можете ви пояснити, чому це краще, ніж звертатися до dict ? Документація на Python є менш ніж корисною, тим більше, що зазвичай вона використовує термін attributesзамість members(чи є різниця між ними?). Вони могли зафіксувати ім’я в Python 3.0, щоб зробити його послідовним.
nikow

Ой, значить __dict__, вибачте.
nikow

4
@nikow: inspect.getmembers () гарантовано продовжує працювати, навіть якщо зміниться внутрішня інформація.
Георг Шеллі

3
@NicholasKnight inspect.getmembers()обгортає dir()з (переважно незначними) побічними перевагами (A), включаючи атрибути динамічного класу та атрибути метакласу та (B), виключаючи членів, що не відповідають пройденому предикату. Позіхання, правда? inspect.getmembers()підходить для сторонніх бібліотек, що підтримують усі можливі типи об'єктів. Для стандартних випадків використання, однак, dir()абсолютно достатньо.
Сесіль Карі

66

dir()це простий спосіб. Дивіться тут:

Керівництво по інтроспекції Python


2
Щось зауважити в документах Python, оскільки dir () надається в першу чергу як зручність для використання в інтерактивному запиті, він намагається надати цікавий набір імен більше, ніж намагається подати суворо або послідовно визначений набір імен, і його детальна поведінка може змінюватися в різних версіях. Наприклад, атрибути метакласу відсутні у списку результатів, коли аргументом є клас.
skyler

1
ця відповідь найкраща при виконанні подряпин на кліпі.

15 років пітона (не повний робочий день ніколи), і я все одно забуваю dir()дякувати.
Абхішек Дуджарі

14

__dict__Властивість об'єкта представляє собою словник усіх інших його певних властивостей. Зауважте, що класи Python можуть змінювати getattr і створювати речі, схожі на властивості, але не входять __dict__. Там також функції BUILTIN vars()і dir()які відрізняються тонкими способами. І __slots__може замінити __dict__в деяких незвичних заняттях.

Об'єкти складні в Python. __dict__є правильним місцем для початку програмування у стилі рефлексії. dir()це місце для початку, якщо ви злому в інтерактивній оболонці.


print vars.__doc__що вказує на те, With an argument, equivalent to object.__dict__якими були б найтонші відмінності?
sancho.s ReinstateMonicaCellio


10

Якщо ви шукаєте відображення всіх властивостей, відповіді вище чудові.

Якщо ви просто хочете отримати ключі словника (який відрізняється від 'об’єкта' в Python), використовуйте

my_dict.keys()

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

1
незважаючи на те, що це моя відповідь, я не думаю, що це має бути прийнятою відповіддю: ключі об’єкта відрізняються від властивості об'єкта-екземпляра класу. До них звертаються по-різному ( obj['key']проти obj.property), і питання стосується властивостей об'єкта. Я даю тут свою відповідь, тому що між ними існує легка плутанина.
MrE

Я б фактично запропонував би зняти цю відповідь.
Енте

Як було сказано вище, люди, що походять з Javascript або C #, наприклад, легко плутають термінологію, оскільки між цими двома поняттями немає різниці. Люди, які вивчають пітон і намагаються отримати доступ до ключів, дуже ймовірно шукають "властивості" і опиняються тут, отже, чому я думаю, що це належить.
ГРЕ

і ви праві, але пропустіть суть: в інших мовах (візьміть JS) немає різниці між об'єктом і словником. ОП походить від 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є динамічним (пор. декоратор властивостей) і 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'}всіх трьох, але не методами чи магією.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.