Как перечислить свойства объекта в Python?

133

IC # мы делаем это через отражение. В Javascript это просто:

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

Как это сделать на Python?

Джадер Диас
источник
3
Обратите внимание, что это неправильный ответ. Большинство ответов касается перечисления членов . Я искал способ перечислить свойства , то есть члены класса, украшенного @property.
Tomasz

Ответы:

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

Имейте в виду, что в некоторых редких случаях есть __slots__свойство, у таких классов часто нет __dict__.

Георг Шёлли
источник
1
как теперь изменить значение? в Javascript вы можете сделать: object [property] = newValue. Как это сделать на Python?
Jader Dias
39
используйте вместо этого setattr ().
Нельсон,
1
@ Нельсон Не могли бы вы объяснить, почему это лучший вариант? Это просто короче, или есть дополнительные соображения?
WhyNotHugo 06
8
@Hugo: Во-первых, потому что он «питонический», другими словами, это синтаксис, который ожидает увидеть большинство сообщества. Другой синтаксис, скорее всего, излишне задержит любого, кто читает ваш код. Во-вторых, некоторые типы реализуют сеттер __setattr__(). Установка значений непосредственно в словаре обходит установщик объекта (и / или его родителей). В python довольно часто случается, что в фоновом режиме во время установки атрибутов происходит больше вещей, чем кажется на первый взгляд (например, санитария), использование setattr()гарантирует, что вы не пропустите или будете вынуждены обрабатывать их явно самостоятельно.
Майкл Экока
3
@ Привет-Ангел. Это действительно работает. Что не работает, так это совокупность предубеждений и предположений, которые у вас есть в отношении статуса по сравнению с членами динамических объектов в 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), кстати.
Нельсон,
Не могли бы вы объяснить, почему это лучше, чем доступ к dict ? Документация Python менее чем полезна, особенно потому, что обычно в ней используется термин attributesвместо members(есть ли разница между ними?). Они могли бы исправить имя в Python 3.0, чтобы оно было согласованным.
nikow
Ой, значит __dict__, извини.
nikow
4
@nikow: inspect.getmembers () гарантированно продолжит работать, даже если внутренние детали изменятся.
Георг Шелли,
3
@NicholasKnight inspect.getmembers()обертывание dir()с незначительными ( в основном) побочными выгодами от (А) , включая атрибуты динамического класса и атрибуты метакласса и (B) за исключение членов , не совпадающих переданный предикат. Зевая, правда? inspect.getmembers()подходит для сторонних библиотек, в целом поддерживающих все возможные типы объектов. Однако для стандартных случаев использования этого dir()вполне достаточно.
Сесил Карри
66

dir()это простой способ. Посмотреть здесь:

Руководство по самоанализу Python

EBGreen
источник
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
11

Георг Шолли, укороченная версия

print vars(theObject)
Николас Рохо
источник
10

Если вы ищете отражение всех свойств, ответы выше отлично подходят.

Если вы просто хотите получить ключи словаря (который отличается от «объекта» в Python), используйте

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']
MRE
источник
1
хотя это мой ответ, я не думаю, что это должен быть принятый ответ: ключи объекта отличаются от свойства экземпляра объекта класса. К ним обращаются по-разному ( obj['key']vs. obj.property), и вопрос был о свойствах объекта. Я поставил здесь свой ответ, потому что их легко перепутать.
MrE
Я бы действительно предложил удалить этот ответ.
Ente
Как указано выше, люди, использующие, например, Javascript или C #, легко запутаются в терминологии, поскольку между этими двумя концепциями нет разницы. Люди, изучающие Python и пытающиеся получить доступ к ключам, очень часто ищут «свойства» и попадают сюда, поэтому я думаю, что он принадлежит.
MrE
и вы правы, но упускаете суть: в других языках (возьмем JS) нет различия между объектом и словарем. OP исходит из C #, задающего вопрос. Этот ответ, хотя и неправильный, получил 11 голосов, что доказывает, что люди, которые попадают сюда, находят его полезным, хотя технически это не правильный ответ (как я указываю) на вопрос, если смотреть на него на строгом языке Python. Я отредактирую, чтобы было еще четче.
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'}все три, но не методы и не магию.

Маттео Ферла
источник