Wyświetl atrybuty obiektu


330

Czy istnieje sposób na pobranie listy atrybutów istniejących w instancjach klasy?

class new_class():
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

a = new_class(2)
print(', '.join(a.SOMETHING))

Pożądanym rezultatem jest wyprowadzenie „multi, str”. Chcę, aby zobaczył bieżące atrybuty z różnych części skryptu.


75
Praktycznie każdy w Pythonie nazywa swoje klasy NewClass. Możesz przeciwstawić się oczekiwaniom ludzi, jeśli zastosujesz taką konwencję nazewnictwa new_class.
Mike Graham,

Mimo że jest interaktywny dla człowieka i nie można go programowo używać, help()funkcja pomaga uzyskać informacje o klasach, funkcjach, wbudowanych modułach i nie tylko
ytpillai


Dlaczego żadna z odpowiedzi nie jest oznaczona jako „Zaakceptowana”?
pfabri

Odpowiedzi:


295
>>> class new_class():
...   def __init__(self, number):
...     self.multi = int(number) * 2
...     self.str = str(number)
... 
>>> a = new_class(2)
>>> a.__dict__
{'multi': 4, 'str': '2'}
>>> a.__dict__.keys()
dict_keys(['multi', 'str'])

Pomocny może być również pprint .


29
Problem użycia dict pojawił się właśnie na r / python. ktoś zauważył, że vars (a) jest równoważny z .__ dict__
David

5
Jeśli ktoś się zastanawia, działa to również w Pythonie 2.7
Ben Mordecai,

8
Aby być konkretnym, pprint.pprint(a.__dict__)robi ładny wydruk na atrybutach.
smci

1
Zdecydowanie pprintto NIE działa w Pythonie 2.6.
John Greene,

3
Zauważ, że działa to tylko dla klas zdefiniowanych przez użytkownika, a nie dla typów wbudowanych lub rozszerzeń.
ivan_pozdeev

173
dir(instance)
# or (same value)
instance.__dir__()
# or
instance.__dict__

Następnie możesz przetestować, jaki typ jest za pomocą type()lub czy jest to metoda za pomocą callable().


dir działał lepiej na klasach z przeciążonym atrybutem get / set
ogurets

reż (instancja) wymienia wiele rzeczy, które prawdopodobnie Cię nie interesują
jciloa

To była jedyna funkcja, która bostondała mi wszystkie dostępne atrybuty w zbiorze danych od sklearn - __dict__była pusta, podczas gdy w rzeczywistości było 5 dostępnych atrybutów
Coruscate5


53

Wszystkie poprzednie odpowiedzi są poprawne, masz trzy opcje na to, o co pytasz

  1. dir()

  2. vars()

  3. __dict__

>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']
>>> vars(a)
{'multi': 4, 'str': '2'}
>>> a.__dict__
{'multi': 4, 'str': '2'}

1
vars(foo)zwrotyfoo.__dict__
Boris

32
>>> ', '.join(i for i in dir(a) if not i.startswith('__'))
'multi, str'

To oczywiście wydrukuje dowolne metody lub atrybuty w definicji klasy. Możesz wykluczyć metody „prywatne”, zmieniając i.startwith('__')nai.startwith('_')


24

Sprawdzić moduł zapewnia proste sposoby przeprowadzenia inspekcji obiektu:

Moduł inspekcji udostępnia kilka przydatnych funkcji, które pomagają uzyskać informacje o obiektach aktywnych, takich jak moduły, klasy, metody, funkcje, elementy śledzące, obiekty ramek i obiekty kodu.


Za pomocą getmembers()możesz zobaczyć wszystkie atrybuty swojej klasy wraz z ich wartością. Aby wykluczyć atrybuty prywatne lub chronione, użyj .startswith('_'). Aby wykluczyć metody lub funkcje, użyj inspect.ismethod()lub inspect.isfunction().

import inspect


class NewClass(object):
    def __init__(self, number):
        self.multi = int(number) * 2
        self.str = str(number)

    def func_1(self):
        pass


a = NewClass(2)

for i in inspect.getmembers(a):
    # Ignores anything starting with underscore 
    # (that is, private and protected attributes)
    if not i[0].startswith('_'):
        # Ignores methods
        if not inspect.ismethod(i[1]):
            print(i)

Zauważ, że ismethod()jest używany na drugim elemencie, iponieważ pierwszy jest po prostu łańcuchem (jego nazwą).

Offtopic: Użyj CamelCase dla nazw klas.


13

Możesz użyć, dir(your_object)aby uzyskać atrybuty i getattr(your_object, your_object_attr)uzyskać wartości

stosowanie :

for att in dir(your_object):
    print (att, getattr(your_object,att))

Jest to szczególnie przydatne, jeśli Twój obiekt nie ma __dict__. Jeśli tak nie jest, możesz także spróbować var ​​(twój_obiekt)


11

Często wspomina się, że aby wyświetlić pełną listę atrybutów, których należy użyć dir(). Zauważ jednak, że wbrew powszechnemu przekonaniu dir()nie ujawnia wszystkich atrybutów. Na przykład możesz zauważyć, że __name__może brakować na dir()liście klas, nawet jeśli możesz uzyskać do niej dostęp z samej klasy. Z poziomu dokumentu dir()( Python 2 , Python 3 ):

Ponieważ dir () jest dostarczany przede wszystkim jako wygoda do użycia w interaktywnym pytaniu, próbuje dostarczyć interesujący zestaw nazw bardziej niż stara się podać rygorystycznie lub konsekwentnie zdefiniowany zestaw nazw, a jego szczegółowe zachowanie może się zmieniać w różnych wydaniach. Na przykład atrybuty metaklasy nie znajdują się na liście wyników, gdy argumentem jest klasa.

Funkcja taka jak poniżej jest zazwyczaj bardziej kompletna, chociaż nie ma gwarancji kompletności, ponieważ na listę zwracaną przez dir()może wpływać wiele czynników, w tym implementacja __dir__()metody, dostosowanie __getattr__()lub __getattribute__()klasa lub jedno z jej rodziców. Zobacz podane linki, aby uzyskać więcej informacji.

def dirmore(instance):
    visible = dir(instance)
    visible += [a for a in set(dir(type)).difference(visible)
                if hasattr(instance, a)]
    return sorted(visible)

9

Po co to chcesz? Uzyskiwanie najlepszej odpowiedzi może być trudne bez znajomości swoich intencji.

  • Prawie zawsze lepiej jest to zrobić ręcznie, jeśli chcesz wyświetlić instancję swojej klasy w określony sposób. Dotyczy to dokładnie tego, czego chcesz, a nie tego, czego nie chcesz, a kolejność będzie przewidywalna.

    Jeśli szukasz sposobu wyświetlania zawartości klasy, ręcznie sformatuj atrybuty, na których Ci zależy, i podaj jako metodę __str__lub __repr__metodę dla swojej klasy.

  • Jeśli chcesz dowiedzieć się, jakie metody istnieją i aby obiekt mógł zrozumieć, jak to działa, użyj help. help(a)pokaże sformatowane dane wyjściowe na temat klasy obiektu na podstawie jego dokumentów.

  • diristnieje, aby programowo uzyskać wszystkie atrybuty obiektu. (Accessing __dict__robi coś, co zgrupowałbym jako to samo, ale którego sam nie użyłbym.) Może to jednak nie obejmować rzeczy, które chcesz, i może obejmować rzeczy, których nie chcesz. Jest niewiarygodny i ludzie myślą, że chcą tego częściej niż oni.

  • Z nieco ortogonalnej nuty, obecnie wsparcie dla Pythona 3 jest bardzo małe. Jeśli jesteś zainteresowany pisaniem prawdziwego oprogramowania, będziesz potrzebować rzeczy innych firm, takich jak numpy, lxml, Twisted, PIL lub dowolna liczba frameworków, które nie obsługują jeszcze Python 3 i nie planują zbyt szybko. Różnice między wersją 2.6 a gałęzią 3.x są niewielkie, ale różnica w obsłudze bibliotek jest ogromna.


4
Chciałbym tylko zauważyć, że pięć lat później (teraz) uważam, że wszystkie moduły innych firm, o których wspomniałeś, obsługują python3. Źródło: python3wos.appspot.com
pzkpfw

8

Jest na to więcej niż jeden sposób:

#! /usr/bin/env python3
#
# This demonstrates how to pick the attiributes of an object

class C(object) :

  def __init__ (self, name="q" ):
    self.q = name
    self.m = "y?"

c = C()

print ( dir(c) )

Po uruchomieniu ten kod generuje:

jeffs@jeff-desktop:~/skyset$ python3 attributes.py 
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__',      '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'm', 'q']

jeffs@jeff-desktop:~/skyset$

2
Dlaczego ta odpowiedź została odrzucona? Do celów debugowania dir działa całkiem dobrze!
Dunatotatos

Pretty współpracuje z Python 2.7.x. Dokładnie to, czego chciałem.
Davidson Lima,

7

Zobacz skrypt powłoki Pythona, który został wykonany sekwencyjnie, tutaj otrzymasz atrybuty klasy w formacie łańcuchowym oddzielone przecinkami.

>>> class new_class():
...     def __init__(self, number):
...         self.multi = int(number)*2
...         self.str = str(number)
... 
>>> a = new_class(4)
>>> ",".join(a.__dict__.keys())
'str,multi'<br/>

Używam Pythona 3.4


A jeśli chcesz, tylko lista może użyć a.__dict__.keys(). Jeśli jednak chcesz wiedzieć, czy obiekt ma określony atrybut, możesz go użyć hasattr.
berna1111

4

Oprócz tych odpowiedzi dołączę funkcję (python 3) do wyrzucania praktycznie całej struktury dowolnej wartości. Służy dirdo ustalenia pełnej listy nazw właściwości, a następnie używa getattrkażdej nazwy. Wyświetla typ każdego elementu wartości, a jeśli to możliwe, wyświetla również cały element:

import json

def get_info(obj):

  type_name = type(obj).__name__
  print('Value is of type {}!'.format(type_name))
  prop_names = dir(obj)

  for prop_name in prop_names:
    prop_val = getattr(obj, prop_name)
    prop_val_type_name = type(prop_val).__name__
    print('{} has property "{}" of type "{}"'.format(type_name, prop_name, prop_val_type_name))

    try:
      val_as_str = json.dumps([ prop_val ], indent=2)[1:-1]
      print('  Here\'s the {} value: {}'.format(prop_name, val_as_str))
    except:
      pass

Teraz każdy z poniższych powinien dać wgląd:

get_info(None)
get_info('hello')

import numpy
get_info(numpy)
# ... etc.

Wow, to klejnot!
pfabri

tak, to był ratownik. nie mogłem zrozumieć, dlaczego nie mogłem łatwo rozpakować tych list i upewnić się, że odpowiedni typ ma właściwość „ sloty ” typu „tuple” Oto wartość slotów : [„nsname”, „hostmaster”, „serial”, „refresh”, „retry”, „expires”, „minttl”, „ttl”]
Mik R

3

Uzyskaj atrybuty obiektu

class new_class():
    def __init__(self, number):
    self.multi = int(number) * 2
    self.str = str(number)

new_object = new_class(2)                
print(dir(new_object))                   #total list attributes of new_object
attr_value = new_object.__dict__         
print(attr_value)                        #Dictionary of attribute and value for new_class                   

for attr in attr_value:                  #attributes on  new_class
    print(attr)

Wynik

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__','__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'multi', 'str']

{'multi': 4, 'str': '2'}

multi
str

1

Jak napisano przed użyciem, obj.__dict__może obsługiwać typowe przypadki, ale niektóre klasy nie mają __dict__atrybutu i zastosowania __slots__(głównie ze względu na wydajność pamięci).

przykład bardziej odpornego sposobu:

class A(object):
    __slots__ = ('x', 'y', )
    def __init__(self, x, y):
        self.x = x
        self.y = y


class B(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y


def get_object_attrs(obj):
    try:
        return obj.__dict__
    except AttributeError:
        return {attr: getattr(obj, attr) for attr in obj.__slots__}


a = A(1,2)
b = B(1,2)
assert not hasattr(a, '__dict__')

print(get_object_attrs(a))
print(get_object_attrs(b))

wyjście tego kodu:

{'x': 1, 'y': 2}
{'x': 1, 'y': 2}

Uwaga 1:
Python jest językiem dynamicznym i zawsze lepiej jest znać klasy, z których próbujesz uzyskać atrybuty, ponieważ nawet ten kod może przeoczyć niektóre przypadki.

Uwaga 2:
ten kod wyprowadza tylko zmienne instancji, co oznacza, że ​​zmienne klas nie są dostarczane. na przykład:

class A(object):
    url = 'http://stackoverflow.com'
    def __init__(self, path):
        self.path = path

print(A('/questions').__dict__)

kod wyjściowy:

{'path': '/questions'}

Ten kod nie drukuje urlatrybutu klasy i może pomijać pożądane atrybuty klasy.
Czasami możemy myśleć, że atrybut jest członkiem instancji, ale nie jest i nie będzie pokazany na tym przykładzie.


2
Klasa może mieć __dict__ i __slots__ dlatego prawdopodobnie chcesz wypróbować oba, a nie tylko dyktando.
cz

1
  • Używanie __dict__lub vars nie działa, ponieważ gubi się __slots__.
  • Używanie __dict__i __slots__ nie działa, ponieważ brakuje __slots__klas podstawowych.
  • Korzystanie dir nie działa, ponieważ obejmuje atrybuty klas, takie jak metody lub właściwości, a także atrybuty obiektu.
  • Używanie varsjest równoważne użyciu __dict__.

To najlepsze, co mam:

from typing import Dict

def get_attrs( x : object ) -> Dict[str, object]:
    mro      = type( x ).mro()
    attrs    = { }
    has_dict = False
    sentinel = object()

    for klass in mro:
        for slot in getattr( klass, "__slots__", () ):
            v = getattr( x, slot, sentinel )

            if v is sentinel:
                continue

            if slot == "__dict__":
                assert not has_dict, "Multiple __dicts__?"
                attrs.update( v )
                has_dict = True
            else:
                attrs[slot] = v

    if not has_dict:
        attrs.update( getattr( x, "__dict__", { } ) )

    return attrs

Zastosujmy tę funkcję do spome prostej klasy: klasa C: def __init __ (self): print („utworzono”) i = 42 Dlaczego twój kod podaje pustą listę dla takiej klasy? (Mam na myśli, jeśli o = C (), to get_attrs (o) jest pusty) Tak samo było w przypadku get_attrs („mystr”)
ged

0
attributes_list = [attribute for attribute in dir(obj) if attribute[0].islower()]

Nie działa z nazwami atrybutów klasy rozpoczynającymi się od dużej litery lub pojedynczego podkreślenia.
fviktor

0

Zobacz sekwencję wykonywania skryptów powłoki Pythona w sekwencjach, da to rozwiązanie od utworzenia klasy do wyodrębnienia nazw pól instancji.

>>> class Details:
...       def __init__(self,name,age):
...           self.name=name
...           self.age =age
...       def show_details(self):
...           if self.name:
...              print "Name : ",self.name
...           else:
...              print "Name : ","_"
...           if self.age:
...              if self.age>0:
...                 print "Age  : ",self.age
...              else:
...                 print "Age can't be -ve"
...           else:
...              print "Age  : ","_"
... 
>>> my_details = Details("Rishikesh",24)
>>> 
>>> print my_details
<__main__.Details instance at 0x10e2e77e8>
>>> 
>>> print my_details.name
Rishikesh
>>> print my_details.age
24
>>> 
>>> my_details.show_details()
Name :  Rishikesh
Age  :  24
>>> 
>>> person1 = Details("",34)
>>> person1.name
''
>>> person1.age
34
>>> person1.show_details
<bound method Details.show_details of <__main__.Details instance at 0x10e2e7758>>
>>> 
>>> person1.show_details()
Name :  _
Age  :  34
>>>
>>> person2 = Details("Rob Pike",0)
>>> person2.name
'Rob Pike'
>>> 
>>> person2.age
0
>>> 
>>> person2.show_details()
Name :  Rob Pike
Age  :  _
>>> 
>>> person3 = Details("Rob Pike",-45)
>>> 
>>> person3.name
'Rob Pike'
>>> 
>>> person3.age
-45
>>> 
>>> person3.show_details()
Name :  Rob Pike
Age can't be -ve
>>>
>>> person3.__dict__
{'age': -45, 'name': 'Rob Pike'}
>>>
>>> person3.__dict__.keys()
['age', 'name']
>>>
>>> person3.__dict__.values()
[-45, 'Rob Pike']
>>>

Możemy również sprawdzić, czy są dostępne dla poszczególnych atrybutów.
Odwiedź

-4

__attr__ podaje listę atrybutów instancji.

>>> import requests
>>> r=requests.get('http://www.google.com')
>>> r.__attrs__
['_content', 'status_code', 'headers', 'url', 'history', 'encoding', 'reason', 'cookies', 'elapsed', 'request']
>>> r.url
'http://www.google.com/'
>>>

Nie zawsze działa Piszecie także __attr__w opisie, ale używacie go __attrs__w kodzie. Żadne z nich nie działało dla mnie (werkzeug.datastructures.FileStorage)
Jonas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.