获取类的属性

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

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


def myfunc(self):
return self.a

使用 MyClass.__dict__给出了一个属性和函数的列表,甚至还有像 __module____doc__这样的函数。除非我显式地设置了该实例的属性值,否则 MyClass().__dict__给我的是一个空的 dict。

我只想要属性,在上面的例子中,它们是: ab

450854 次浏览

MyClass().__class__.__dict__

然而,正确的做法是通过 检查模块检查模块

尝试 视察模块。 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')]

更复杂的方法包括特殊的属性名检查,甚至元类检查;)

myfunc MyClass的一个属性。这就是当你运行:

myinstance = MyClass()
myinstance.myfunc()

它在 myinstance上查找一个名为 myfunc的属性,但是没有找到,它看到 myinstanceMyClass的一个实例并在那里查找它。

因此 MyClass完整属性列表是:

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

(注意,我使用 dir 只是为了快速简单地列出类的成员: 它应该只用于探索性的方式,而不是用于生产代码)

如果您只想要特定的属性,那么您需要使用一些标准来过滤这个列表,因为 __doc____module__myfunc在任何方面都不特殊,它们的属性方式与 ab完全相同。

我从来没有使用过 Matt 和 Borealid 提到的查看模块,但是从一个简短的链接来看,它似乎有测试来帮助你做到这一点,但是你需要编写自己的谓词函数,因为它似乎你想要的是大致的属性,不要通过 isroutine测试,不开始和结束两个下划线。

还要注意的是: 在 Python 2.7中使用 class MyClass():就是在使用过时的老式类。除非您是为了与极其古老的库兼容而故意这样做,否则您应该将类定义为 class MyClass(object):。在 Python3中没有“旧式”类,这种行为是默认的。然而,使用 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']
def props(cls):
return [i for i in cls.__dict__.keys() if i[:1] != '_']


properties = props(MyClass)

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

class_name.attribute

没问题。

我的解决方案是获取一个类的所有属性(而不是方法)(如果该类有一个正确编写的文档字符串,其中清楚地写出了属性) :

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

这段代码 cls.__dict__['__doc__']提取类的 docstring。

我最近需要找出一些类似的问题,所以我想张贴一些背景信息,可能有助于其他人面临同样的未来。

下面是它在 Python 中的工作原理(来自 https://docs.python.org/3.5/reference/datamodel.html#the-standard-type-hierarchy) :

MyClass是类对象,MyClass()是类对象的实例。实例的 __dict__只保存特定于该实例的属性和方法(例如 self.somethings)。如果一个属性或方法是类的一部分,那么它就在类的 __dict__中。当执行 MyClass().__dict__时,创建的 MyClass实例除了 class 属性之外没有其他属性或方法,因此是空的 __dict__

因此,如果您说 print(MyClass().b),Python 首先检查新实例的 dictMyClass().__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()

但是 静态方法不总是 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()应该是 < a href = “ https://docs.python.org/3/library/function tions.html
但不是在这个 愚蠢又简单例子中。

测试结果

$ 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

如果您想“获取”一个属性,那么有一个 答案很简单,它应该是显而易见的: 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 中都很好用。

如果您想要一个这些项目的列表,您仍然需要使用检查。

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

我不知道现在是否已经做了类似的东西,但我使用 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个属性。我使用它来搜索需要查看的特定属性。

我想这可以不用检查就能完成。

参加以下课程:

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

你可以使用 MyClass.__attrs__。它只是给出了这个类的所有属性。仅此而已。

Python 2 & 3,whitout 导入,根据地址过滤对象

简而言之,解决方案:

返回 < em > dict { tribute _ name: tribute _ 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)}

返回 List [ tribute _ Names ] 列表[属性 _ 名称] ,过滤的对象即 ['a', 'b', 'c', 'd']

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

返回 List [ tribute _ 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条件。返回 < code > {‘ a’: 1,‘ c’: [3,3] ,‘ b’: (2,2) ,‘ e’: < function < lambda > at 0x7fc8a870fd70 > ,‘ d’: {4:4} ,‘ f’: < object at 0x7fc8abe130e0 > }

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

很快就能解决了

只要 __repr__的默认实现没有被覆盖 ,如果 val内存中位置的十六进制表示在 __repr__返回字符串中,那么 if语句将返回 True

关于 __repr__的默认实现,你可以找到有用的 这个答案。简而言之:

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

它返回一个字符串,如:

<__main__.Bar object at 0x7f3373be5998>

通过 id()方法得到每个元素在存储器中的位置。

Python Docs 介绍了 id () :

返回对象的“标识”。这是一个整数,它保证在此对象的生命周期内是唯一和常数。两个生存期不重叠的对象可能具有相同的 id ()值。

CPython 实现细节: 这是 记忆。


你自己试试

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

产出:

{'a': 1, 'c': [3, 3], 'b': (2, 2), 'd': {4: 4}}

注意 :

  • 使用 Python2.7.13和 Python3.5.3进行测试

  • 在 Python 2.x 中,.iteritems()优于 .items()

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

import enum


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

列出你的特点? 没有比这更容易的了:

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

以下就是我想要的。

测试数据

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

快速函数获取非魔法属性及其值的属性。

这个实用程序的用法只是快速地自省一下 Class 或 Object,而不需要深入研究代码或文档。 当我使用它的时候,我只是想知道这个类所拥有的东西,并且区分什么是函数,什么不是,很明显,我不记得我为什么需要它。

例如,我使用了 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~,但实际上任何东西都可以使用。

from faker import Faker
fake = Faker()


def get_class_props(cls):
for p in dir(cls):
if not p.startswith('__'):
attr_value = getattr(cls, p)
if p.startswith('_'):
print(f'- {p} (private): {attr_value}')
else:
print(f'- {p}: {attr_value}')


get_class_props(fake)


- _factories (private): [<faker.generator.Generator object at 0x00000138D01D28C8>]
# - _factory_map (private): OrderedDict([('en_US', <faker.generator.Generator object at 0x00000138D01D28C8>)])
# - _locales (private): ['en_US']
# - _map_provider_method (private): <bound method Faker._map_provider_method of <faker.proxy.Faker object at 0x00000138D017AD88>>
# - _select_factory (private): <bound method Faker._select_factory of <faker.proxy.Faker object at 0x00000138D017AD88>>
# - _unique_proxy (private): <faker.proxy.UniqueProxy object at 0x00000138D017A308>
# - _weights (private): None
# - aba: <bound method Provider.aba of <faker.providers.bank.en_GB.Provider object at 0x00000138D281DBC8>>
# - add_provider: <bound method Generator.add_provider of <faker.generator.Generator object at 0x00000138D01D28C8>>
# - address: <bound method Provider.address of <faker.providers.address.en_US.Provider object at 0x00000138D2810DC8>>
# ...

要清理函数定义,可以使用这个变体,其中定义了“ function”,不管它是什么可调用的

from faker import Faker
fake = Faker()


def get_class_props(cls):
for p in dir(cls):


if not p.startswith('__'):
attr_value = getattr(cls, p)
is_function = callable(attr_value)


if p.startswith('_'):
print(f'- {p} (private): {attr_value if not is_function else "funciton"}')
else:
print(f'- {p}: {attr_value if not is_function else "funciton"}')




- _factories (private): [<faker.generator.Generator object at 0x0000018A11D49C48>]
- _factory_map (private): OrderedDict([('en_US', <faker.generator.Generator object at 0x0000018A11D49C48>)])
- _locales (private): ['en_US']
- _map_provider_method (private): funciton
- _select_factory (private): funciton
- _unique_proxy (private): <faker.proxy.UniqueProxy object at 0x0000018A11D49748>
- _weights (private): None
- aba: funciton
get_class_props(fake)

在上面的答案中添加过滤功能:

import inspect
import re


def getClassMembers(obj, name=None, mbrcat='all'):
# name : filter by attribute name
# mbrcat : filter members by items category : all, methods or attributes
dic_cat= {
'all' : lambda a: a,
'meth' : lambda a: inspect.isroutine(a),
'attr' : lambda a:  not(inspect.isroutine(a))
}
return [str(_name)+'  :  '+str(member)
for _name, member in inspect.getmembers(obj, dic_cat[mbrcat])
if ((name==None) or (name in _name)) and (not(re.search(r'(^\_\_|\_\_$)' ,_name))) ]

电话号码一:

getClassMembers(myClass.browse(264917),'state')


#Output:
['_compute_activity_state  :  <bound method xxx._compute_activity_state of classXXX >'
'extract_state  :  no_extract_requested',
'invoice_payment_state  :  paid',
'state  :  posted'
]

电话号码2:

getClassMembers(myClass.browse(264917),'state','meth')


#Output:
['_compute_activity_state  :  <bound method xxx._compute_activity_state of classXXX >'
]

电话号码3:

getClassMembers(myClass.browse(264917),'state','attr')
#Ouput:
[
'extract_state  :  no_extract_requested',
'invoice_payment_state  :  paid',
'state  :  posted'
]