获取所有可能的类属性的完整列表

时间:2015-10-12 18:26:15

标签: python python-3.x attributes python-2.x

有一种方法,给定一个简单的类,输出所有可能的属性吗?标准属性,如__class____doc__ special read only attributes,如__mro____bases__等。通常, 所有 目前属性?

考虑类的最简单的情况:

class myClass:
    pass

dir()vars()inspect.getmembers()都排除了某些builtin属性。最完整的列表是使用myClass.__dir__(MyClass)提供的,MyClass在添加内置属性时会排除用户定义的In [3]: set(MyClass.__dir__(MyClass)) - set(dir(MyClass)) Out[3]: {'__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__dictoffset__', '__flags__', '__instancecheck__', '__itemsize__', '__mro__', '__name__', '__prepare__', '__qualname__', '__subclasscheck__', '__subclasses__', '__text_signature__', '__weakrefoffset__', 'mro'} 属性,例如:

__bases__

根据其中一个类似的问题,这是不可能的。如果目前还不可能,隐藏"背后的理由是什么? 某些属性,例如dir(), vars() & inspect(来自标准调用__name__而不是Python 2.x

类似的问题:

1 个答案:

答案 0 :(得分:4)

dir()基本上是一种方便的方法,它不应该返回所有内容,它基本上做的是它递归地返回在类的字典及其基础中找到的所有内容。

PyPy's implementation of dir()很容易理解:

def dir(*args):
    ...
    elif isinstance(obj, (types.TypeType, types.ClassType)):
        # Don't look at __class__, as metaclass methods would be confusing.
        return sorted(_classdir(obj))
    ...

def _classdir(klass):
    """Return a set of the accessible attributes of class/type klass.

    This includes all attributes of klass and all of the base classes
    recursively.
    """
    names = set()
    ns = getattr(klass, '__dict__', None)
    if ns is not None:
        names.update(ns)
    bases = getattr(klass, '__bases__', None)
    if bases is not None:
        # Note that since we are only interested in the keys, the order
        # we merge classes is unimportant
        for base in bases:
            names.update(_classdir(base))
    return names

由于每个班级基本上都是从object继承而来,你会看到一些dunder方法,因为它们实际上是object词典的一部分:

>>> class A(object):
    pass
...
>>> set(dir(A)) == set(list(object.__dict__) + list(A.__dict__))
True
  

那么__bases__和其他缺少的项目呢?

首先,object本身就是某个事件的实例,well it's bit of a mess actually

>>> isinstance(type, object)
True
>>> isinstance(object, type)
True
>>> issubclass(type, object)
True
>>> issubclass(object, type)
False
>>> type.mro(object)
[<type 'object'>]
>>> type.mro(type)
[<type 'type'>, <type 'object'>]

因此,__bases____ge__等所有属性实际上都是type的一部分:

>>> list(type.__dict__)
['__module__', '__abstractmethods__', '__getattribute__', '__weakrefoffset__', '__dict__', '__lt__', '__init__', '__setattr__', '__subclasses__', '__new__', '__base__', '__mro__', 'mro', '__dictoffset__', '__call__', '__itemsize__', '__ne__', '__instancecheck__', '__subclasscheck__', '__gt__', '__name__', '__eq__', '__basicsize__', '__bases__', '__flags__', '__doc__', '__delattr__', '__le__', '__repr__', '__hash__', '__ge__']

因此,当我们A.__bases__时,我们实际上正在查找descriptor on type of A,即type

>>> A.__bases__
(<type 'object'>,)
>>> type(A).__dict__['__bases__'].__get__(A, type)
(<type 'object'>,)

因此,Atype的一个实例,这些方法不属于自己的字典,而是其类型的字典。

>> class A(object):
...     spam = 'eggs'
...
>>> a = A()
>>> a.foo = 100
>>> a.bar = 200
>>> a.__dict__
{'foo': 100, 'bar': 200}
>>> A.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'A' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'spam': 'eggs'})

由于typeobject的子类,dir()上的type调用将包含object中的一些项目:

>>> set(dir(type)) - set(type.__dict__)
set(['__reduce_ex__', '__str__', '__format__', '__reduce__', '__class__', '__subclasshook__', '__sizeof__'])