Uzyskiwanie atrybutów klasy

Chcę uzyskać atrybuty klasy, powiedzmy:

class MyClass():
  a = "12"
  b = "34"

  def myfunc(self):
    return self.a

Użycie MyClass.__dict__ daje mi listę atrybutów i funkcji, a nawet funkcji takich jak __module__ i __doc__. While MyClass().__dict__ daje mi pusty dict, chyba że jawnie ustawię wartość atrybutu tej instancji.

Chcę tylko atrybuty, w powyższym przykładzie będą to: a i b

Author: Mohamed Khamis, 2012-01-30

14 answers

Wypróbuj moduł inspect . getmembers i różne testy powinny być pomocne.

EDIT:

Na przykład,

class MyClass(object):
    a = '12'
    b = '34'
    def myfunc(self):
        return self.a

>>> import inspect
>>> inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
[('__class__', type),
 ('__dict__',
  <dictproxy {'__dict__': <attribute '__dict__' of 'MyClass' objects>,
   '__doc__': None,
   '__module__': '__main__',
   '__weakref__': <attribute '__weakref__' of 'MyClass' objects>,
   'a': '34',
   'b': '12',
   'myfunc': <function __main__.myfunc>}>),
 ('__doc__', None),
 ('__module__', '__main__'),
 ('__weakref__', <attribute '__weakref__' of 'MyClass' objects>),
 ('a', '34'),
 ('b', '12')]

Teraz specjalne metody i atrybuty działają mi na nerwy - z nimi można sobie poradzić na wiele sposobów, z których najprostszym jest filtrowanie na podstawie nazwy.

>>> attributes = inspect.getmembers(MyClass, lambda a:not(inspect.isroutine(a)))
>>> [a for a in attributes if not(a[0].startswith('__') and a[0].endswith('__'))]
[('a', '34'), ('b', '12')]

...a bardziej skomplikowane z nich mogą zawierać specjalne sprawdzanie nazw atrybutów lub nawet metaklasy;)

 73
Author: Matt Luongo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-13 18:38:58
def props(cls):   
  return [i for i in cls.__dict__.keys() if i[:1] != '_']

properties = props(MyClass)
 23
Author: Doug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-22 09:31:05

myfunc jest atrybutem MyClass. Tak to się dzieje kiedy biegasz:

myinstance = MyClass()
myinstance.myfunc()

Szuka atrybutu na myinstance o nazwie myfunc, nie znajduje żadnego, widzi, że myinstance jest instancją MyClass i szuka go tam.

Więc pełna lista atrybutów dla MyClass to:

>>> dir(MyClass)
['__doc__', '__module__', 'a', 'b', 'myfunc']

(zauważ, że używam dir tylko jako szybki i łatwy sposób na listę członków klasy: powinien być używany tylko w sposób rozpoznawczy, a nie w produkcji kod)

Jeśli chcesz tylko określonych atrybutów, musisz filtrować tę listę przy użyciu pewnych kryteriów, ponieważ __doc__, __module__, i myfunc nie są w żaden sposób wyjątkowe, są atrybutami W dokładnie taki sam sposób, jak a i b.

Nigdy nie używałem modułu inspect, o którym mowa przez Matta i Borealida, ale z krótkiego linku wygląda na to, że ma testy, które pomogą Ci to zrobić, ale musisz napisać własną funkcję predykatu, ponieważ wydaje się, że to, co chcesz, to mniej więcej atrybuty, które Nie przechodzą test isroutine i nie zaczynają się i nie kończą dwoma podkreślnikami.

Uwaga: używając class MyClass(): w Pythonie 2.7 używasz szalenie nieaktualnych klas starego stylu. O ile nie robisz tego celowo dla kompatybilności z bardzo starymi bibliotekami, powinieneś zamiast tego zdefiniować swoją klasę jako class MyClass(object):. W Pythonie 3 nie ma klas "starego stylu" , a to zachowanie jest domyślne. Jednak korzystanie z klas newstyle da ci dużo więcej automatycznie zdefiniowane atrybuty:

>>> class MyClass(object):
        a = "12"
        b = "34"
        def myfunc(self):
            return self.a
>>> dir(MyClass)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'a', 'b', 'myfunc']
 16
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-30 02:05:18

MyClass().__class__.__dict__

Jednak, "prawo" było zrobić to za pomocą inspect module.

 5
Author: Borealid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-30 01:06:37

Nie wiem, czy coś podobnego zostało już zrobione, czy nie, ale zrobiłem ładną funkcję wyszukiwania atrybutów za pomocą Vars (). vars () tworzy słownik atrybutów klasy, przez którą przechodzisz.

class Player():
    def __init__(self):
        self.name = 'Bob'
        self.age = 36
        self.gender = 'Male'

s = vars(Player())
#From this point if you want to print all the attributes, just do print(s)

#If the class has a lot of attributes and you want to be able to pick 1 to see
#run this function
def play():
    ask = input("What Attribute?>: ")
    for key, value in s.items():
        if key == ask:
            print("self.{} = {}".format(key, value))
            break
    else:
        print("Couldn't find an attribute for self.{}".format(ask))

Rozwijam całkiem ogromną przygodę z tekstem w Pythonie, moja klasa graczy ma do tej pory ponad 100 atrybutów. Używam tego do wyszukiwania konkretnych atrybutów, które muszę zobaczyć.

 3
Author: Corey Bailey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-24 19:16:25

Moje rozwiązanie, aby uzyskać wszystkie atrybuty (Nie metody) klasy

def get_class_attrs(cls):
    return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
 1
Author: Henry On,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-22 22:13:14

Ostatnio musiałem wymyślić coś podobnego do tego pytania, więc chciałem opublikować kilka informacji, które mogą być pomocne dla innych, którzy staną przed tym samym w przyszłości.

Oto Jak to działa w Pythonie (od https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy):

MyClass jest obiektem klasy, {[1] } jest instancją obiektu klasy. Instancja __dict__ przechowuje tylko atrybuty i metody specyficzne dla tej instancji(np. self.somethings). Jeśli atrybut lub metoda jest częścią klasy, należy do klasy __dict__. Gdy wykonasz MyClass().__dict__, instancja MyClass jest tworzona bez atrybutów lub metod poza atrybutami klasy, a więc pusta __dict__

Więc jeśli powiesz print(MyClass().b), Python najpierw sprawdza dict nowej instancji MyClass().__dict__['b'] i nie znajduje b. Następnie sprawdza klasę MyClass.__dict__['b'] i znajduje b.

Dlatego potrzebny jest moduł inspect, aby emulować ten sam proces wyszukiwania.

 1
Author: Scott Howard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-09 18:33:24
import re

class MyClass:
    a = "12"
    b = "34"

    def myfunc(self):
        return self.a

attributes = [a for a, v in MyClass.__dict__.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

Dla przykładu MyClass, np.

mc = MyClass()

Użyj type(mc) w miejsce MyClass na liście. Jeśli jednak dynamicznie dodamy atrybut mc, na przykład mc.c = "42", atrybut nie pojawi się podczas używania type(mc) w tej strategii. Daje tylko atrybuty oryginalnej klasy.

Aby uzyskać kompletny słownik dla instancji klasy, musisz połączyć słowniki type(mc).__dict__ i mc.__dict__.

mc = MyClass()
mc.c = "42"

# Python 3.5
combined_dict = {**type(mc).__dict__, **mc.__dict__}

# Or Python < 3.5
def dict_union(d1, d2):
    z = d1.copy()
    z.update(d2)
    return z

combined_dict = dict_union(type(mc).__dict__, mc.__dict__)

attributes = [a for a, v in combined_dict.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]
 1
Author: JD Graham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-20 00:46:01

Uzyskanie tylko atrybutów instancji jest łatwe.
Ale uzyskanie atrybutów klasy BEZ funkcji jest nieco trudniejsze.

Tylko atrybuty instancji

Jeśli musisz tylko wymienić atrybuty instancji po prostu użyj
for attribute, value in my_instance.__dict__.items()

>>> from __future__ import (absolute_import, division, print_function)
>>> class MyClass(object):
...   def __init__(self):
...     self.a = 2
...     self.b = 3
...   def print_instance_attributes(self):
...     for attribute, value in self.__dict__.items():
...       print(attribute, '=', value)
...
>>> my_instance = MyClass()
>>> my_instance.print_instance_attributes()
a = 2
b = 3
>>> for attribute, value in my_instance.__dict__.items():
...   print(attribute, '=', value)
...
a = 2
b = 3

Instancja i atrybuty klasy

Aby uzyskać również atrybuty klasy BEZ funkcji, sztuczka polega na użyciu callable().

Ale statyczne metody nie zawsze callable!

Dlatego zamiast używać callable(value) użyj
callable(getattr(MyClass, attribute))

Przykład

from __future__ import (absolute_import, division, print_function)

class MyClass(object):
   a = "12"
   b = "34"               # class attributes

   def __init__(self, c, d):
     self.c = c
     self.d = d           # instance attributes

   @staticmethod
   def mystatic():        # static method
       return MyClass.b

   def myfunc(self):      # non-static method
     return self.a

   def print_instance_attributes(self):
     print('[instance attributes]')
     for attribute, value in self.__dict__.items():
        print(attribute, '=', value)

   def print_class_attributes(self):
     print('[class attributes]')
     for attribute in MyClass.__dict__.keys():
       if attribute[:2] != '__':
         value = getattr(MyClass, attribute)
         if not callable(value):
           print(attribute, '=', value)

v = MyClass(4,2)
v.print_class_attributes()
v.print_instance_attributes()

Uwaga: print_class_attributes() powinno być @staticmethod
      ale nie w tym głupim i prostym przykładzie.

Wynik dla python2

$ python2 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2

Ten sam wynik dla python3

$ python3 ./print_attributes.py
[class attributes]
b = 34
a = 12
[instance attributes]
c = 4
d = 2
 1
Author: olibre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-28 18:10:18

Istnieje bardzo prosta odpowiedź , która powinna być oczywista: getattr

class MyClass(object):
a = '12'
b = '34'
def myfunc(self):
    return self.a

>>> getattr(MyClass, 'a')
'12'

>>> getattr(MyClass, 'myfunc')
<function MyClass.myfunc at 0x10de45378>

Działa świetnie zarówno w Pythonie 2.7 jak i Pythonie 3.x.

Jeśli chcesz mieć listę tych elementów, nadal musisz użyć programu inspect.

 0
Author: fralau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-20 13:43:41

Możesz użyć dir() w liście aby uzyskać nazwy atrybutów:

names = [p for p in dir(myobj) if not p.startswith('_')]

Użyj getattr(), aby uzyskać same atrybuty:

attrs = [getattr(myobj, p) for p in dir(myobj) if not p.startswith('_')]
 0
Author: Rotareti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-13 14:18:24

To można zrobić bez inspekcji, tak myślę.

Weź następującą klasę:

 class Test:
   a = 1
   b = 2

   def __init__(self):
     self.c = 42

   @staticmethod
   def toto():
     return "toto"

   def test(self):
     return "test"

Patrząc na członków wraz z ich typami:

t = Test()
l = [ (x, eval('type(x.%s).__name__' % x)) for x in dir(a) ]

... daje:

[('__doc__', 'NoneType'),
 ('__init__', 'instancemethod'),
 ('__module__', 'str'),
 ('a', 'int'),
 ('b', 'int'),
 ('c', 'int'),
 ('test', 'instancemethod'),
 ('toto', 'function')]

Więc aby wypisać tylko zmienne, musisz filtrować wyniki według typu i nazw nie zaczynających się od'__'. Np.

filter(lambda x: x[1] not in ['instancemethod', 'function'] and not x[0].startswith('__'), l)

[('a', 'int'), ('b', 'int'), ('c', 'int')] # actual result
To wszystko.

Uwaga: Jeśli używasz Pythona 3, przekonwertuj Iteratory na listy.

Jeśli chcesz bardziej solidny sposób, aby to zrobić, użyj inspect .

 0
Author: carmellose,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-21 12:28:12

Dwie Funkcje:

def get_class_attr(Cls) -> []:
    import re
    return [a for a, v in Cls.__dict__.items()
              if not re.match('<function.*?>', str(v))
              and not (a.startswith('__') and a.endswith('__'))]

def get_class_attr_val(cls):
    attr = get_class_attr(type(cls))
    attr_dict = {}
    for a in attr:
        attr_dict[a] = getattr(cls, a)
    return attr_dict

Użycie:

>>> class MyClass:
    a = "12"
    b = "34"
    def myfunc(self):
        return self.a

>>> m = MyClass()
>>> get_class_attr_val(m)
{'a': '12', 'b': '34'}
 0
Author: redscarf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-23 05:09:05

Wiem, że to było trzy lata temu, ale dla tych, którzy w przyszłości będą mieli to pytanie, dla mnie:

class_name.attribute 
Działa dobrze.
 -3
Author: Jim Jam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-20 02:47:55