这个协议定义在哪里?

时间:2013-08-12 13:13:42

标签: python protocols

说我们这样做:

class thing(object):
    pass

然后我>>> thing.__eq__,然后我得到<method-wrapper '__eq__' of type object at 0x0E8B68D0>。但是如果我们执行'__eq__' in dir(thing),我会得到一个NameError异常,说明__eq__没有定义,但是如果它没有定义,那我怎么得到一个方法包装返回,显然是它定义的,但如果dir看不到它,它在哪里定义?

3 个答案:

答案 0 :(得分:2)

dir(thing)返回方法名称的列表,所有字符串。使用实际字符串进行测试:

'__eq__' in dir(thing) 

这仍将返回False,因为dir()仅列出了最重要方法的摘要。您还必须在thing的元类上另外列出所有内容,在本例中为type

>>> '__eq__' in dir(type(thing))
True

引用dir()的文档:

  

注意:因为提供dir() 主要是为了方便在交互式提示中使用,所以它会尝试提供一个有趣的   一组名称超过它试图严格或一致地提供   定义的名称集,其详细行为可能会发生变化   版本。例如, metaclass属性不在结果中   列表当参数是一个类时。

强调我的。

__eq__是此处的后备实施; type()定义了一个合理的默认值(退回到身份测试,==实现为is),只要您的自定义类没有实现自定义版本,即没有意思并列出它只会不必要地混淆dir()的结果。

答案 1 :(得分:1)

dir未列出所有属性:

The docs说:

  

结果列表不一定完整......   默认的dir()机制对不同类型的行为有所不同   对象,因为它试图产生最相关的,而不是   完整,信息......

     

因为提供dir()主要是为了方便使用   交互式提示,它试图提供一组有趣的名称   不只是它试图提供严格或一致定义的集合   名称及其详细行为可能会在不同版本中发生变化。对于   例如,元类属性不在结果列表中   论证是一个阶级。


此外,我假设您测试了'__eq__' in dir(thing) - 请注意引号 - 因为dir会返回字符串列表。


ジョージ shows根据rlcompleter模块中的代码列出所有属性的方法:

import rlcompleter

def get_object_attrs(obj):
    """
    based on code from the rlcompleter module
    See https://stackoverflow.com/a/10313703/190597 (ジョージ)
    """
    ret = dir(obj)
    ## if "__builtins__" in ret:
    ##    ret.remove("__builtins__")
    if hasattr(obj, '__class__'):
        ret.append('__class__')
        ret.extend(rlcompleter.get_class_members(obj.__class__))
        ret = list(set(ret))
    return ret

class Thing(object):
    pass

print(get_object_attrs(Thing))

打印

['__module__', '__format__', '__itemsize__', '__str__', '__reduce__', '__weakrefoffset__', '__dict__', '__sizeof__', '__weakref__', '__lt__', '__init__', '__setattr__', '__reduce_ex__', '__subclasses__', '__new__', '__abstractmethods__', '__class__', '__mro__', '__base__', '__bases__', '__dictoffset__', '__call__', '__doc__', '__ne__', '__getattribute__', '__instancecheck__', '__subclasscheck__', '__subclasshook__', '__gt__', '__name__', '__eq__', 'mro', '__basicsize__', '__flags__', '__delattr__', '__le__', '__repr__', '__hash__', '__ge__']

我们可以从中Thing获取dir未列出的>>> print(set(get_object_attrs(Thing)) - set(dir(Thing))) set(['__ne__', '__abstractmethods__', '__subclasses__', '__eq__', '__instancecheck__', '__base__', '__flags__', '__mro__', '__le__', '__basicsize__', '__bases__', '__dictoffset__', '__weakrefoffset__', '__call__', '__name__', '__lt__', '__subclasscheck__', '__gt__', '__itemsize__', '__ge__', 'mro']) 中的属性列表:

get_class_members(cls)

cls收集来自cls 的属性以及dir 的所有基础。

因此,要获得更完整的属性列表,必须将{{1}}添加到对象类的属性,以及对象类的基础的所有属性。

答案 2 :(得分:1)

原因是Python 2如何处理__eq__。 请查看this thread以获取更多信息。

在python 3中,'__eq__'返回的方法名称列表中的内容发生了变化(no more __cmp__ method)和dir(thing)