Como saber se um objeto tem um atributo em Python


1635

Existe uma maneira no Python para determinar se um objeto tem algum atributo? Por exemplo:

>>> a = SomeClass()
>>> a.someProperty = value
>>> a.property
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: SomeClass instance has no attribute 'property'

Como você pode saber se atem o atributo propertyantes de usá-lo?

Respostas:


2343

Tente hasattr():

if hasattr(a, 'property'):
    a.property

EDIT: Veja a resposta de zweiterlinde abaixo, que oferece bons conselhos sobre pedir perdão! Uma abordagem muito pitônica!

A prática geral em python é que, se é provável que a propriedade esteja lá a maior parte do tempo, simplesmente chame-a e deixe a exceção se propagar, ou prenda-a com um bloco try / except. Provavelmente será mais rápido que hasattr. Se a propriedade provavelmente não estiver lá a maior parte do tempo, ou você não tiver certeza, o uso hasattrprovavelmente será mais rápido do que cair repetidamente em um bloco de exceção.


19
Parece estar a trabalhar para a verificação de funções no espaço de nomes, bem como, por exemplo: import string hasattr(string, "lower")
riviera

15
hasattré exatamente o mesmo que usar try/ except AttributeError: a docstring do hasattr (no Python 2.7) diz que ele usa a mão getattr captura exceções.
Jeff Tratner

8
@ JeffTratner: hasattrinfelizmente não é exatamente o mesmo que try: ... except AttributeError:no Python 2.x, já hasattrque capturará todas as exceções . Por favor, veja minha resposta para um exemplo e uma solução simples.
Martin Geisler

632

Como Jarret Hardie respondeu, hasattrfará o truque. Gostaria de acrescentar, no entanto, que muitos na comunidade Python recomendam uma estratégia "mais fácil pedir perdão do que permissão" (EAFP) do que "olhar antes de pular" (LBYL). Veja estas referências:

EAFP vs LBYL (Re: um pouco decepcionado até agora)
EAFP vs LBYL @Code Como um Pythonista: Idiomatic Python

ou seja:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

... é preferido para:

if hasattr(a, 'property'):
    doStuff(a.property)
else:
    otherStuff()

258
Mas como você verifica se foi a a.property que causou AttributeError, e não algo em doStuff ()? Parece que você não. Eu acho que é realmente mais fácil pedir perdão, mas muitas vezes também é incorreto.
Jsp4.jpg

285
O EAFP parece ... louco. O HasAttr telégrafo para futuros programadores de manutenção que você está procurando por um atributo específico. Obter uma exceção não diz nada aos futuros programadores e pode levar alguém à toca do coelho.
Ethan Heilman

74
@ e5: você tem um ponto justo nesse caso, mas em muitos casos o EAFP é a única opção correta. Por exemplo, se você verificar a existência de um arquivo e abri-lo, esperando que ele definitivamente exista, seu código está incorreto: o arquivo pode ser excluído ou renomeado entre a verificação e o uso. Isso é chamado de erro TOCTOU (horário do check-in-time-of-use) e, além de causar falhas, também pode ser uma fonte de vulnerabilidades de segurança.
Max

15
@ EthanHeilman é insano quando há ambiguidade na fonte da exceção, o que pode ser evitado com bom design na maioria dos casos. A estruturação da lógica em camadas dentro de try / except / finalmente geralmente cria uma lógica mais robusta (menos propensa a erros de programadores) do que desarrumar o código com verificações if-preventivas para cada parte do código consumido. Torna os erros muito explícitos também e permite que os programadores consumidores consigam lidar com eles diretamente.
Peter M. Elias

64
A maioria das reclamações de ambiguidade aqui são simplesmente porque o código de exemplo é mal estruturado. A única coisa dentro do try:deve ser a tentativa de acesso ao atributo; não há razão para encerrar a execução doStufftambém. No entanto, ainda existe algum potencial de ambiguidade: se propertyfor uma propriedade calculada em vez de um atributo simples, sua implementação poderá aumentar AttributeErrorinternamente. É por isso que, em quase todas as situações reais como essa, getattré preferível a um hasattrou a outro AttributeError.
Carl Meyer

485

Você pode usar hasattr()ou capturar AttributeError, mas se você realmente deseja apenas o valor do atributo com um padrão, se ele não estiver lá, a melhor opção é usar getattr():

getattr(a, 'property', 'default value')

14
Isso resolve os dois problemas mencionados acima: a) A ambiguidade da fonte de um possível AttributeError, b) Preservando a abordagem do EAFP.
Peter M. Elias

6
Também é 25% das linhas de código. Certamente, essa deve ser a melhor solução.
Fatuhoku 24/09

16
Esta é a melhor solução "se você realmente deseja apenas o valor do atributo com um padrão". Embora eu acredite que é isso que muitas pessoas realmente querem quando dizem que desejam detectar se um atributo está presente, o OP realmente solicitou o último, portanto, é razoável que as respostas diretas a essa pergunta (hasattr, AttributeError) sejam listadas mais .
Carl Meyer

41

Eu acho que o que você está procurando é hasattr . No entanto, eu recomendaria algo assim se você quiser detectar propriedades python -

try:
    getattr(someObject, 'someProperty')         
except AttributeError:
    print "Doesn't exist"
else
    print "Exists"

A desvantagem aqui é que os erros de atributo no __get__código de propriedades também são capturados.

Caso contrário,

if hasattr(someObject, 'someProp'):
    #Access someProp/ set someProp
    pass

Documentos: http://docs.python.org/library/functions.html
Aviso:
O motivo da minha recomendação é que o hasattr não detecta propriedades.
Link: http://mail.python.org/pipermail/python-dev/2005-December/058498.html


3
hasattrdetecta propriedades em geral muito bem. É apenas que trata de gerar uma exceção na propertyfunção -wrapped como significando que esse atributo não existe; a postagem da lista de discussão em Python vinculada é sobre uma propriedade que gera uma exceção quando você tenta acessá-la. Para todos os fins práticos, o referido atributo não existe, porque nunca produzirá um valor. Além disso, hasattrapenas suprime exceções em geral no Py 3.1 e versões anteriores; em 3.2+, apenas suprime (substituindo por Falsereturn) AttributeError.
ShadowRanger

32

De acordo com o pydoc, o hasattr (obj, prop) simplesmente chama getattr (obj, prop) e captura exceções. Portanto, é tão válido envolver o acesso ao atributo com uma instrução try e capturar o AttributeError quanto usar hasattr () antecipadamente.

a = SomeClass()
try:
    return a.fake_prop
except AttributeError:
    return default_value

2
Bem, o hasattr pode ser otimizado. Por exemplo, com pypy.
odinho - Velmont 18/08/11

6
+1. Isso é ainda mais seguro do que usar hasattrquando SomeClasssubstituições, __getattr__pois hasattrcapturará todas as exceções no Python 2.x, não exatamente AttributeErrorcomo você esperaria. Isso foi corrigido no Python 3.2 - consulte minha outra resposta para uma solução alternativa simples.
Martin Geisler

24

Eu gostaria de sugerir evitar isso:

try:
    doStuff(a.property)
except AttributeError:
    otherStuff()

O usuário @jpalecek mencionou: Se AttributeErrorocorrer um dentro doStuff(), você estará perdido.

Talvez essa abordagem seja melhor:

try:
    val = a.property
except AttributeError:
    otherStuff()
else:
    doStuff(val)

13

Dependendo da situação, você pode verificar com isinstanceque tipo de objeto você possui e, em seguida, usar os atributos correspondentes. Com a introdução de classes base abstratas no Python 2.6 / 3.0, essa abordagem também se tornou muito mais poderosa (basicamente os ABCs permitem uma maneira mais sofisticada de digitação de patos).

Uma situação em que isso é útil seria se dois objetos diferentes tivessem um atributo com o mesmo nome, mas com significado diferente. Usando apenashasattr pode levar a erros estranhos.

Um bom exemplo é a distinção entre iteradores e iterables (consulte esta pergunta). Os __iter__métodos em um iterador e um iterável têm o mesmo nome, mas são semanticamente bem diferentes! Então hasattré inútil, masisinstance junto com o ABC fornece uma solução limpa.

No entanto, concordo que, na maioria das situações, a hasattrabordagem (descrita em outras respostas) é a solução mais apropriada.


13

Espero que você esteja esperando hasattr (), mas tente evitar hasattr () e, por favor, prefira getattr (). getattr () é mais rápido que hasattr ()

usando hasattr ():

 if hasattr(a, 'property'):
     print a.property

mesmo aqui estou usando getattr para obter propriedade, se não houver propriedade, ele retornará nenhum

   property = getattr(a,"property",None)
    if property:
        print property

11

EDIT : Esta abordagem tem sérias limitações. Deverá funcionar se o objeto for iterável . Por favor, verifique os comentários abaixo.

Se você estiver usando o Python 3.6 ou superior como eu, há uma alternativa conveniente para verificar se um objeto tem um atributo específico:

if 'attr1' in obj1:
    print("attr1 = {}".format(obj1["attr1"]))

No entanto, não tenho certeza de qual é a melhor abordagem no momento. usando hasattr(), usando getattr()ou usando in. Comentários são bem-vindos.


6
inA palavra-chave funciona para verificar tipos iteráveis. Por exemplo, 'foo' in Nonelança o erro TypeError: argument of type 'NoneType' is not iterable. A correção é verificar se o tipo é iterável antes de usar in. Depois de corrigir casos de arestas como o tipo não iterável, você provavelmente está melhor usando, hasattr()pois ele foi projetado para lidar com casos de arestas.
Seth Difley 5/10

3
Isso não tem nada a ver com acesso a atributos. Não tenho ideia de como foi votado. A única semelhança que ele tem para atribuir acesso é se você estiver usando dictcomo um "objeto leve", semelhante ao design de objetos JavaScript, mas a maioria das classes normais não suportará isso em geral (obtendo uma variante do erro mencionado por @SethDifley) .
ShadowRanger


1

Isso é super simples, basta usar o dir(objeto.)
Isso retornará uma lista de todas as funções e atributos disponíveis do objeto.


1

Outra opção possível, mas depende se o que você quer dizer com antes :

undefined = object()

class Widget:

    def __init__(self):
        self.bar = 1

    def zoom(self):
        print("zoom!")

a = Widget()

bar = getattr(a, "bar", undefined)
if bar is not undefined:
    print("bar:%s" % (bar))

foo = getattr(a, "foo", undefined)
if foo is not undefined:
    print("foo:%s" % (foo))

zoom = getattr(a, "zoom", undefined)
if zoom is not undefined:
    zoom()

resultado:

bar:1
zoom!

Isso permite que você verifique se há atributos sem valor.

Mas! Tenha muito cuidado para não instanciar acidentalmente e comparar undefinedvários locais, porque isnunca funcionará nesse caso.

Atualizar:

por causa do que eu estava avisando no parágrafo acima, tendo vários indefinidos que nunca correspondem, recentemente modifiquei ligeiramente esse padrão:

undefined = NotImplemented

NotImplemented, para não confundir NotImplementedError, é um built-in: ele combina semitendamente a intenção de um JS undefinede você pode reutilizar sua definição em qualquer lugar e sempre corresponderá. A desvantagem é que ele é "verdadeiro" nos booleanos e pode parecer estranho nos logs e nos rastreamentos de pilha (mas você rapidamente supera isso quando sabe que só aparece nesse contexto).


0

Você pode verificar se objectcontém atributo usando o hasattrmétodo interno.

Por exemplo, se seu objeto é ae você deseja verificar o atributostuff

>>> class a:
...     stuff = "something"
... 
>>> hasattr(a,'stuff')
True
>>> hasattr(a,'other_stuff')
False

A própria assinatura do método é hasattr(object, name) -> boolo que significa que se objecttem atributo que é passado para o segundo argumento em hasattrque ele dá booleana Trueou Falsede acordo com a presença de nameatributo no objecto.


0

hasattr()é a resposta certa. O que eu quero acrescentar é que hasattr()também pode ser usado bem em conjunto com assert (para evitar ifdeclarações desnecessárias e tornar o código mais legível):

assert hasattr(a, 'property'), 'object lacks property' 

Conforme indicado em outra resposta no SO : As declarações devem ser usadas para testar condições que nunca devem acontecer. O objetivo é travar no início no caso de um estado de programa corrompido.


Isso é útil, mas nem sempre é o caso. Talvez eu quisesse testar se o objeto tem uma propriedade e adicioná-la pela primeira vez, ou talvez eu precise executar um código diferente para objetos com essa propriedade. Quando o código não pode continuar, a declaração pode estar correta. Mas, novamente, nem sempre é o caso. O importante é o uso de hasattrnão o código circundante.
Lucas Gabriel Sánchez
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.