如果自定义__dir__实现,如何获取对象名称的实际列表?

时间:2012-12-16 05:10:45

标签: python internals

官方文档says

  

如果对象具有名为__dir__()的方法,则将调用此方法   并且必须返回属性列表。这允许对象   实现自定义__getattr__()__getattribute__()功能   自定义dir()报告其属性的方式。

如果自定义__dir__已实施,则由另一个功能inspect.getmembers()返回的结果也会受到影响。

例如:

class С(object):
    __slots__ = ['atr']
    def __dir__(self):
        return ['nothing']
    def method(self):
        pass
    def __init__(self):
        self.atr = 'string'

c = C() 
print dir(f) #If we try this - well get ['nothing'] returned by custom __dir__()
print inspect.getmembers(f) #Here we get []
print f.__dict__ #And here - exception will be raised because of __slots__

在这种情况下,如何获取对象名称列表?

2 个答案:

答案 0 :(得分:4)

对原始问题的回答 - inspect.getmembers()使用像__dir__()这样的dir()吗?

以下是inspect.getmembers()的源代码,因此我们可以看到它的确在做什么:

def getmembers(object, predicate=None):
    """Return all members of an object as (name, value) pairs sorted by name.                                                                                                                                     
    Optionally, only return members that satisfy a given predicate."""
    results = []
    for key in dir(object):
        try:
            value = getattr(object, key)
        except AttributeError:
            continue
        if not predicate or predicate(value):
            results.append((key, value))
    results.sort()
    return results

从此我们看到 使用dir(),只是过滤了一些结果。

如何使用被覆盖的__dir__()获取属性?

根据this answer,不可能始终获得完整的属性列表,但我们仍然可以在某些情况下获得它们/得到足够的有用。

来自the docs

  

如果对象未提供__dir__(),则该函数会尝试最佳   从对象的__dict__属性收集信息,如果   定义,并从其类型对象。结果列表不是   必须完成,并且当对象具有时可能不准确   自定义__getattr__()

因此,如果您没有使用__slots__,您可以查看对象的__dict__(以及它的类型对象),以获得dir()通常会给您的相同信息。因此,就像使用dir()一样,您必须使用更严格的方法来获取元类方法。

如果您使用的是__slots__,那么获取类属性在某种程度上会更简单一些。是的,没有字典,但有__slots__本身,其中包含所有属性的名称。例如,将print c.__slots__添加到示例代码中会产生['atr']。 (同样,需要更严格的方法来获取超类的属性。)

如何获取方法

根据用例,您可能需要不同的解决方案,但如果您只想轻松找到方法,则只需使用内置help()

修改后的PyPy dir()

以上是上述部分内容的替代方法:要获取忽略用户定义的dir()方法的__dir__版本,您只需dir() __dir__和{{1}}删除引用{{1}}方法的部分。

答案 1 :(得分:0)

正如Matthew在另一个答案中所指出的那样,getmembers显然会返回属于实际属性的dir结果的子集。

>>> class C:
>>>   def foo(self):
>>>     pass
>>>   def __dir__(self):
>>>     return ['test']
>>>
>>> import inspect
>>> c = C()
>>> dir(c)
['test']
>>> inspect.getmembers(c)
[]