获取类的属性

时间:2012-01-30 01:03:09

标签: python python-2.7 class attributes

我想获得一个类的属性,比如说:

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

  def myfunc(self):
    return self.a

使用MyClass.__dict__为我提供了属性和函数列表,甚至是__module____doc__等函数。虽然MyClass().__dict__给了我一个空的dict,除非我明确设置了该实例的属性值。

我只想要上面示例中的属性:ab

19 个答案:

答案 0 :(得分:85)

尝试inspect模块。 getmembers并且各种测试应该会有所帮助。

编辑:

例如,

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

...其中更复杂的可以包括特殊属性名称检查甚至元类;)

答案 1 :(得分:28)

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

properties = props(MyClass)

答案 2 :(得分:17)

myfunc 属性为MyClass。这就是你跑步时的表现:

myinstance = MyClass()
myinstance.myfunc()

它会在名为myinstance的{​​{1}}上找到一个属性,找不到一个,看到myfuncmyinstance的一个实例并在那里查找。< / p>

因此MyClass完整属性列表是:

MyClass

(请注意,我正在使用dir作为列出类成员的快捷方式:它应该只以探索方式使用,而不是在生产代码中使用)

如果您只想要特定属性,则需要使用某些条件过滤此列表,因为>>> dir(MyClass) ['__doc__', '__module__', 'a', 'b', 'myfunc'] __doc____module__在任何方面都不特殊, “属性与myfunca完全相同。

我从未使用过Matt和Borealid所引用的inspect模块,但是从一个简短的链接看起来它有测试可以帮助你做到这一点,但你需要编写自己的谓词函数,因为它似乎您想要的大致是通过b测试的属性,并且不以两个下划线开头和结尾。

另请注意:在Python 2.7中使用isroutine,您使用的是过时的旧式类。除非您故意这样做以便与极其旧的库兼容,否则您应该将您的类定义为class MyClass():。在Python 3中没有“旧式”类,这种行为是默认的。但是,使用newstyle类将为您提供 lot 更自动定义的属性:

class MyClass(object):

答案 3 :(得分:6)

MyClass().__class__.__dict__

但是,“正确”是通过inspect module来实现的。

答案 4 :(得分:2)

我获取类的所有属性(而不是方法)的解决方案(如果类具有正确编写的文档字符串,其中明确说明了属性):

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

这篇文章cls.__dict__['__doc__']提取了该类的文档字符串。

答案 5 :(得分:2)

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

答案 6 :(得分:2)

只获取实例属性非常简单 但是在没有函数的情况下获得类属性也有点棘手。

仅限实例属性

如果您只需列出实例属性,只需使用
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()

static methodsnot always callable

因此,而不是使用callable(value)使用
callablegetattrMyClass, 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 ./print_attributes.py
[class attributes]
a = 12
b = 34
[instance attributes]
c = 4
d = 2

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

答案 7 :(得分:2)

我不知道现在是否有类似的东西,但我使用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开发一个非常庞大的Text Adventure,到目前为止,我的Player类有超过100个属性。我用它来搜索我需要查看的特定属性。

答案 8 :(得分:1)

我最近需要找出类似于这个问题的内容,所以我想发布一些背景信息,这些信息可能对将来面临同样问题的人有所帮助。

以下是它在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模块来模仿相同的搜索过程。

答案 9 :(得分:1)

您可以在列表理解中使用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('_')]

答案 10 :(得分:1)

我想这可以在没有检查的情况下完成。

参加以下课程:

 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,请将迭代器转换为列表。

如果您想要更强大的方法,请使用inspect

答案 11 :(得分:1)

为什么需要列出属性?从语义上看,您的课程是一个集合。在这种情况下,我建议使用enum:

import enum

class myClass(enum.Enum):
     a = "12"
     b = "34"

列出您的属性?没有比这更简单的了:

for attr in myClass:
    print("Name / Value:", attr.name, attr.value)

答案 12 :(得分:1)

Python 2和3,禁止导入,按对象地址过滤对象

简短的解决方案:

返回 dict {attribute_name:attribute_value} ,已过滤对象。即{'a': 1, 'b': (2, 2), 'c': [3, 3]}

{k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}

返回 列表[attribute_names] ,对象已过滤。即['a', 'b', 'c', 'd']

[k for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

返回 列表[attribute_values] ,已过滤对象。即[1, (2, 2), [3, 3], {4: 4}]

[val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)]

不过滤对象

删除if条件。返回{'a': 1, 'c': [3, 3], 'b': (2, 2), 'e': <function <lambda> at 0x7fc8a870fd70>, 'd': {4: 4}, 'f': <object object at 0x7fc8abe130e0>}

{k: val for k, val in self.__dict__.items()}

长期解决方案

只要不重写__repr__的默认实现,如果if语句在内存中以十六进制表示,将返回True {1}}在val返回字符串中。

关于__repr__的默认实现,您会发现有用的this answer。简而言之:

__repr__

Wich返回一个字符串,如:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

每个元素在内存中的位置都是通过<__main__.Bar object at 0x7f3373be5998> 方法获得的。

Python Docs说说id():

  

返回对象的“身份”。这是一个整数,可以保证在此对象的生存期内唯一且恒定。具有不重叠生存期的两个对象可能具有相同的id()值。

     

CPython实现细节:这是对象的地址   记忆。


自己尝试

id()

输出:

class Bar:

    def __init__(self):

        self.a = 1
        self.b = (2, 2)
        self.c = [3, 3]
        self.d = {4: 4}
        self.e = lambda: "5"
        self.f = object()

    #__str__ or __repr__ as you prefer
    def __str__(self):
        return "{}".format(

            # Solution in Short Number 1
            {k: val for k, val in self.__dict__.items() if not str(hex(id(val))) in str(val)}

        )

# Main
print(Bar())

注意

  • 经过Python {'a': 1, 'c': [3, 3], 'b': (2, 2), 'd': {4: 4}} 和Python 2.7.13

  • 的测试
  • 在Python 2.x中,3.5.3胜过.iteritems()

答案 13 :(得分:0)

另一个简单的解决方案:

class Color(const):
    BLUE = 0
    RED = 1
    GREEN = 2

    @classmethod
    def get_all(cls):
        return [cls.BLUE, cls.RED, cls.GREEN]

用法: Color.get_all()

答案 14 :(得分:0)

以下是我想要的。

测试数据

class Base:
    b = 'b'


class MyClass(Base):
    a = '12'

    def __init__(self, name):
        self.name = name

    @classmethod
    def c(cls):
        ...

    @property
    def p(self):
        return self.a

    def my_fun(self):
        return self.name
print([name for name, val in inspect.getmembers(MyClass) if not name.startswith('_') and not callable(val)])  # need `import inspect`
print([_ for _ in dir(MyClass) if not _.startswith('_') and not callable(getattr(MyClass, _))])
# both are equ: ['a', 'b', 'p']

my_instance = MyClass('c')
print([_ for _ in dir(my_instance) if not _.startswith('_') and not callable(getattr(my_instance, _))])
# ['a', 'b', 'name', 'p']

答案 15 :(得分:0)

您可以使用MyClass.__attrs__。它只是给出了该类的所有属性。没什么。

答案 16 :(得分:0)

两个功能:

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

答案 17 :(得分:0)

有一个非常简单的答案,这应该是显而易见的: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。

答案 18 :(得分:-3)

我知道这是三年前的事,但是对于那些将来会遇到这个问题的人,对我来说:

class_name.attribute 

工作正常。