Como enumerar as propriedades de um objeto em Python?

133

IC # fazemos isso através da reflexão. Em Javascript é simples como:

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

Como fazer isso em Python?

Jader Dias
fonte
3
Observe que esta pergunta é inadequada. A maioria das respostas é sobre enumerar membros . Eu estava procurando uma maneira de enumerar propriedades , ou seja, membros de uma classe decorada com @property.
Tomasz Gandor

Respostas:

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

Esteja ciente de que em alguns casos raros existe uma __slots__propriedade, essas classes geralmente não têm __dict__.

Georg Schölly
fonte
1
agora como mudar o valor? em Javascript, você poderia fazer: object [property] = newValue. Como fazer isso em Python?
9119 Jader Dias
39
use setattr () em vez disso.
919 Nelson Nelson
1
@ Nelson Você poderia explicar por que essa é uma opção melhor? É apenas mais curto ou há considerações adicionais?
WhyNotHugo
8
@ Hugo: Primeiro porque é "pitônico", em outras palavras, é a sintaxe que uma grande maioria da comunidade espera ver. A outra sintaxe provavelmente daria uma pausa desnecessária a qualquer pessoa que estivesse lendo seu código. Segundo, alguns tipos implementam um setter __setattr__(). Definir valores diretamente no dicionário ignora o criador do objeto (e / ou o de seus pais). É bastante comum em python que mais coisas do que aparentam estar acontecendo em segundo plano durante a configuração de atributos (por exemplo, saneamento), o uso setattr()garante que você não perca, ou seja forçado a lidar com eles explicitamente.
Michael Ekoka
3
@ Hi-anjo que faz o trabalho. O que não está funcionando, no entanto, é a constelação de preconceitos e suposições que você tem sobre o status e os membros dinâmicos do objeto no Python. vars()retorna apenas membros estáticos (ou seja, atributos e métodos de objetos registrados nos objetos __dict__). Ele não retorna membros dinâmicos (isto é, atributos e métodos de objetos definidos dinamicamente pelo __getattr__()método desse objeto ou magia semelhante). Com toda a probabilidade, sua file.ImplementationNamepropriedade desejada é definida dinamicamente e, portanto, não está disponível para vars()ou dir().
Cecil Curry
69

Veja inspect.getmembers(object[, predicate]).

Retorne todos os membros de um objeto em uma lista de pares (nome, valor) classificados por nome. Se o argumento do predicado opcional for fornecido, apenas os membros para os quais o predicado retorna um valor verdadeiro serão incluídos.

>>> [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']
>>> 
gimel
fonte
Sim, esta resposta é ótima; nunca usei este módulo antes. getmembers () é implementado apenas andando pelos resultados de dir (object), btw.
919 Nelson Nelson
Você pode explicar por que isso é melhor do que acessar o dict ? A documentação do Python é menos que útil, especialmente porque normalmente usa o termo em attributesvez de members(existe alguma diferença entre os dois?). Eles poderiam ter corrigido o nome no Python 3.0 para torná-lo consistente.
nikow
Opa, quis dizer __dict__, desculpe.
nikow
4
@nikow: inspect.getmembers () é garantido para continuar trabalhando, mesmo que os detalhes internos sejam alterados.
Georg Schölly 9/08/09
3
O @NicholasKnight inspect.getmembers()encerra dir()os benefícios colaterais (principalmente desprezíveis) de (A), incluindo atributos de classe dinâmica e atributos de metaclasse e (B) excluindo membros que não correspondem ao predicado passado. Bocejo, certo? inspect.getmembers()é apropriado para bibliotecas de terceiros que oferecem suporte genericamente a todos os tipos de objetos possíveis. Para casos de uso padrão, no entanto, dir()é absolutamente suficiente.
Cecil Curry
66

dir()é a maneira simples. Veja aqui:

Guia para introspecção em Python

EBGreen
fonte
2
Algo a ser observado nos documentos do Python, porque dir () é fornecido principalmente como uma conveniência para uso em um prompt interativo, ele tenta fornecer um conjunto interessante de nomes mais do que tenta fornecer um conjunto de nomes definido de forma rigorosa ou consistente, e seu comportamento detalhado pode mudar entre os releases. Por exemplo, os atributos de metaclasse não estão na lista de resultados quando o argumento é uma classe.
Skyler
1
esta resposta é a melhor quando se faz um trabalho de rascunho no CLI.
15 anos de python (nunca em tempo integral) e ainda me esqueço de dir()agradecer.
Abhishek Dujari 14/06
14

A __dict__propriedade do objeto é um dicionário de todas as suas outras propriedades definidas. Observe que as classes Python podem substituir o getattr e criar coisas que parecem propriedades, mas não estão presentes __dict__. Há também as funções internas vars()e dir()que são diferentes de maneiras sutis. E __slots__pode substituir __dict__em algumas classes incomuns.

Objetos são complicados em Python. __dict__é o lugar certo para começar a programação no estilo de reflexão. dir()é o lugar para começar se você estiver navegando em um shell interativo.

Nelson
fonte
print vars.__doc__indica que With an argument, equivalent to object.__dict__Então, quais seriam as diferenças sutis?
sancho.s ReinstateMonicaCellio
11

georg scholly versão mais curta

print vars(theObject)
Nicolas Rojo
fonte
10

Se você está procurando um reflexo de todas as propriedades, as respostas acima são ótimas.

Se você simplesmente deseja obter as chaves de um dicionário (que é diferente de um 'objeto' no Python), use

my_dict.keys()

my_dict = {'abc': {}, 'def': 12, 'ghi': 'string' }
my_dict.keys() 
> ['abc', 'def', 'ghi']
MrE
fonte
1
mesmo que seja minha resposta, não acho que deva ser a resposta aceita: as chaves de um objeto são diferentes da propriedade de uma instância de objeto de uma classe. Eles são acessados ​​de maneira diferente ( obj['key']vs. obj.property) e a pergunta era sobre propriedades de objetos. Coloquei minha resposta aqui, porque há uma confusão fácil entre os dois.
MrE 17/02/19
Eu realmente sugeriria remover esta resposta.
Ente
Como mencionado acima, pessoas provenientes de Javascript ou C #, por exemplo, são facilmente confundidas com a terminologia, pois não há diferença entre esses dois conceitos. As pessoas que aprendem python e tentam acessar chaves são muito propensas a procurar por 'propriedades' e acabam aqui, por isso acho que ele pertence.
MrE 12/12/19
e você está certo, mas erra o ponto: em outras línguas (veja JS) não há distinção entre objeto e dicionário. O OP vem do C # que faz a pergunta. Essa resposta, apesar de errada, recebeu 11 votos positivos, prova de que as pessoas que chegam aqui acham útil, mesmo que não seja tecnicamente a resposta certa (como aponto) para a pergunta ao analisá-la em linguagem rigorosa de python. Vou editar para torná-lo ainda mais claro.
MrE 13/12/19
5

Isso é totalmente coberto pelas outras respostas, mas vou explicitar. Um objeto pode ter atributos de classe e atributos de instância estáticos e dinâmicos.

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

    def fx(self):
        return 3

stasisé estático, dynodinâmico (cf. decorador de propriedades) e classyé um atributo de classe. Se simplesmente fizermos __dict__ou varsconseguiremos apenas a estática.

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

Então, se quisermos, os outros __dict__receberão tudo (e mais). Isso inclui métodos e atributos mágicos e métodos vinculados normais. Então, vamos evitar os seguintes:

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}

O typechamado com um método decorado de propriedade (um atributo dinâmico) fornecerá o tipo do valor retornado, não method. Para provar isso, vamos definir o json:

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

Se tivesse sido um método, teria colidido.

TL; DR. tente chamar extravar = lambda o: {k: getattr(o, k, '') for k in o.__dir__() if k[:2] != '__' and type(getattr(o, k, '')).__name__ != 'method'}todos os três, mas não métodos nem magia.

Matteo Ferla
fonte