Как перечислить свойства объекта в 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


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']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'}все три, но не методы и не магию.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.