Получение атрибутов класса



Я хочу получить атрибуты класса, скажем:



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

def myfunc(self):
return self.a


используя MyClass.__dict__ дает мне список атрибутов и функций, и даже такие функции, как __module__ и __doc__. В то время как MyClass().__dict__ дает мне пустой dict, если я явно не задал значение атрибута этого экземпляра.



Я просто хочу атрибуты, в приведенном выше примере это будет:a и b

512   14  

14 ответов:

попробовать проверить модуль. getmembers и различные тесты должны быть полезны.

EDIT:

например,

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')]

Теперь специальные методы и атрибуты действуют мне на нервы - с ними можно справиться несколькими способами, Самый простой из которых-просто фильтровать на основе имени.

>>> 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')]

...и более сложные из которых могут включать специальные проверки имен атрибутов или даже метаклассы;)

def props(cls):   
  return [i for i in cls.__dict__.keys() if i[:1] != '_']

properties = props(MyClass)

myfuncи атрибут MyClass. Вот как это обнаруживается при запуске:

myinstance = MyClass()
myinstance.myfunc()

он ищет атрибут myinstance имени myfunc, не находит, видит, что myinstance пример MyClass и смотрит его там.

так полное список атрибутов MyClass - это:

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

(обратите внимание, что я использую dir просто как быстрый и простой способ перечислить членов класса: это должно быть только используется в исследовательском режиме, а не в производственном коде)

Если вам нужны только определенные атрибуты, вам нужно будет отфильтровать этот список, используя некоторые критерии, потому что __doc__,__module__ и myfunc не спец в любом случае, они атрибуты точно так же, как a и b есть.

я никогда не использовал модуль inspect, упомянутый Matt и Borealid, но из краткой ссылки похоже, что у него есть тесты, которые помогут вам это сделать, но вам нужно будет написать ваша собственная функция предиката, так как кажется, что вы хотите, это примерно атрибуты, которые не передать isroutine проверьте и не начинайте и не заканчивайте двумя подчеркиваниями.

обратите внимание: с помощью class MyClass(): в Python 2.7 вы используете дико устаревшие классы старого стиля. Если вы не делаете это намеренно для совместимости с очень старыми библиотеками, вы должны вместо этого определить свой класс как class MyClass(object):. В Python 3 нет классов "старого стиля", и это поведение по умолчанию. Однако, используя классы newstyle вы получите много более автоматически определенные атрибуты:

>>> 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']

MyClass().__class__.__dict__

однако, "право" должно было сделать это через модуль проверить.

Я не знаю, было ли что-то подобное сделано сейчас или нет, но я сделал хорошую функцию поиска атрибутов с помощью vars(). vars () создает словарь атрибутов класса, который вы проходите через него.

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))

Я разрабатываю довольно массивное текстовое приключение в Python, мой класс игрока до сих пор имеет более 100 атрибутов. Я использую это для поиска конкретных атрибутов, которые мне нужно увидеть.

мое решение, чтобы получить все атрибуты (не методов) класса

def get_class_attrs(cls):
    return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])

недавно мне нужно было выяснить что-то похожее на этот вопрос, поэтому я хотел опубликовать некоторую фоновую информацию, которая может быть полезна другим, столкнувшимся с тем же в будущем.

вот как это работает в Python (от https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy):

MyClass является объектом класса, MyClass() является экземпляром объекта класса. Экземпляр __dict__ только держать атрибуты и методы, специфичные для этот экземпляр (например,self.somethings). Если атрибут или метод является частью класса, в классе __dict__. Когда вы делаете MyClass().__dict__ экземпляр MyClass создано без атрибутов или методов, кроме атрибутов класса, таким образом, пустой __dict__

так что если вы говорите print(MyClass().b), Python сначала проверяет dict нового экземпляра MyClass().__dict__['b'] и не удается найти b. Затем он проверяет класс MyClass.__dict__['b'] находит b.

вот почему вам нужен inspect модуль, чтобы повторить тот же самый процесс поиска.

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('__'))]

для экземпляра MyClass, например

mc = MyClass()

использовать type(mc) на месте MyClass в списке понимание. Однако, если динамически добавить атрибут в mc, например mc.c = "42", атрибут не будет отображаться при использовании type(mc) в этой стратегии. Он дает только атрибуты исходного класса.

чтобы получить полный словарь для экземпляра класса, вам нужно будет объединить словари type(mc).__dict__ и 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('__'))]

только атрибуты экземпляра легко.
Но получение также атрибуты класса без функций немного сложнее.

атрибуты экземпляра только

если вы только должны перечислить атрибуты экземпляра просто использовать
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

атрибуты экземпляра и класса

и атрибуты класса без функций, трюк заключается в использовании callable().

но статические методы are не всегда callable!

, вместо callable(value) использовать
callable(getattr(MyClass, attribute))

пример

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()

Примечание:print_class_attributes() должно быть @staticmethod
      но не в этом глупо и просто пример.

результат python2

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

тот же результат для python3

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

есть очень простой ответ, это должно быть очевидно: 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>

Он работает превосходно как в Python 2.7 и Python 3.x.

Если вам нужен список этих элементов, вам все равно нужно будет использовать inspect.

можно использовать dir() на понимание чтобы получить имена атрибутов:

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

использовать getattr() получить сами атрибуты:

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

Это можно сделать без проверки, я думаю.

Возьмите следующий класс:

 class Test:
   a = 1
   b = 2

   def __init__(self):
     self.c = 42

   @staticmethod
   def toto():
     return "toto"

   def test(self):
     return "test"

глядя на членов вместе с их типа:

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

... дает:

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

таким образом, чтобы вывести только переменные, вам просто нужно отфильтровать результаты по типу и имена, не начинающиеся с '__'. Е. Г.

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

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

вот и все.

Примечание: если вы используете Python 3, преобразуйте итераторы в списки.

если вы хотите более надежный способ сделать это, использовать проверить.

две функции:

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

использование:

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

>>> m = MyClass()
>>> get_class_attr_val(m)
{'a': '12', 'b': '34'}

Я знаю, что это было три года назад, но для тех, кто придет к этому вопросу в будущем, для меня:

class_name.attribute 

работает просто отлично.

Comments

    Ничего не найдено.