Jak*_*rde 32 python attributes class introspection inspect
我需要一种方法来检查类,所以我可以放心地识别哪些属性是用户定义的类属性.问题是,像DIR功能(),inspect.getmembers()和朋友返回所有类的属性包括预定义的像:__class__,__doc__,__dict__,__hash__.这当然是可以理解的,而且人们可以说,我只能命名的成员名单忽视,但遗憾的是这些预先定义的属性绑定,因此不同版本的Python使我的项目volnerable在Python项目改改 - 我不喜欢那样.
例:
>>> class A:
...   a=10
...   b=20
...   def __init__(self):
...     self.c=30
>>> dir(A)
['__doc__', '__init__', '__module__', 'a', 'b']
>>> get_user_attributes(A)
['a','b']
在上面的例子中,我想要一种安全的方法来只检索用户定义的类属性['a','b']而不是'c',因为它是一个实例属性.所以我的问题是......任何人都可以帮我解决上述虚构功能get_user_attributes(cls)吗?
PS我花了一些时间试图通过解析AST级别的类来解决问题,这很容易.但我找不到将已解析的对象转换为AST节点树的方法.我想一旦将一个类编译成字节码,就会丢弃所有的AST信息.
最好的问候雅各布
aar*_*ing 30
以下是艰难的方式.这是简单的方法.不知道为什么它不会早点发生在我身上.
import inspect
def get_user_attributes(cls):
    boring = dir(type('dummy', (object,), {}))
    return [item
            for item in inspect.getmembers(cls)
            if item[0] not in boring]
这是一个开始
def get_user_attributes(cls):
    boring = dir(type('dummy', (object,), {}))
    attrs = {}
    bases = reversed(inspect.getmro(cls))   
    for base in bases:
        if hasattr(base, '__dict__'):
            attrs.update(base.__dict__)
        elif hasattr(base, '__slots__'):
            if hasattr(base, base.__slots__[0]): 
                # We're dealing with a non-string sequence or one char string
                for item in base.__slots__:
                    attrs[item] = getattr(base, item)
            else: 
                # We're dealing with a single identifier as a string
                attrs[base.__slots__] = getattr(base, base.__slots__)
    for key in boring:
        del attrs['key']  # we can be sure it will be present so no need to guard this
    return attrs
这应该相当强大.本质上,它通过获取默认子类上的属性object来忽略.然后它获取传递给它的类的mro并以相反的顺序遍历它,以便子类键可以覆盖超类键.它返回键值对的字典.如果你想要一个键列表,像那样的值元组inspect.getmembers只返回attrs.items()或list(attrs.items())在Python 3中.
如果您实际上并不想遍历mro并且只想直接在子类上定义属性,那么它会更容易:
def get_user_attributes(cls):
    boring = dir(type('dummy', (object,), {}))
    if hasattr(cls, '__dict__'):
        attrs = cls.__dict__.copy()
    elif hasattr(cls, '__slots__'):
        if hasattr(base, base.__slots__[0]): 
            # We're dealing with a non-string sequence or one char string
            for item in base.__slots__:
                attrs[item] = getattr(base, item)
            else: 
                # We're dealing with a single identifier as a string
                attrs[base.__slots__] = getattr(base, base.__slots__)
    for key in boring:
        del attrs['key']  # we can be sure it will be present so no need to guard this
    return attrs
'特殊属性'两端的双下划线是2.0之前的python的一部分.它们不太可能在不久的将来随时改变.
class Foo(object):
  a = 1
  b = 2
def get_attrs(klass):
  return [k for k in klass.__dict__.keys()
            if not k.startswith('__')
            and not k.endswith('__')]
print get_attrs(Foo)
['a','b']