Python 的 Magic Methods 指南(5)

用一个字符串来表示一个类往往会非常有用。在Python中,有很多你可以在类定义中实施的方法来自定义内置函数的返回值以表示出你所写出的类的某些行为。

__str__(self)

定义当 str() 被你的一个类的实例调用时所要产生的行为。

__repr__(self)

定义 当 repr() 被你的一个类的实例调用时所要产生的行为。 str() repr() 的主要区别是其目标群体。 repr() 返回的是机器可读的输出,而 str() 返回的是人类可读的。

__unicode__(self)

定义当 unicode() 被你的一个类的实例调用时所要产生的行为。 unicode() str() 很相似,但是返回的是unicode字符串。注意,如果对你的类调用 str() 然而你只定义了 __unicode__() ,那么其将不会工作。你应该定义 __str__() 来确保调用时能返回正确的值,并不是每个人都有心情去使用unicode。

__format__(self, formatstr)

定义当你的一个类的实例被用来用新式的格式化字符串方法进行格式化时所要产生的行为。例如, "Hello, {0:abc}!".format(a) 将会导致调用 a.__format__("abc") 。这对定义你自己的数值或字符串类型是十分有意义的,你可能会给出一些特殊的格式化选项。

__hash__(self)

定义当 hash()被你的一个类的实例调用时所要产生的行为。它返回一个整数,用来在字典中进行快速比较。请注意,这通常也承担着实现__eq__。有下面这样的规则:a == b 暗示着 hash(a) == hash(b) 。

__nonzero__(self)

定义当 bool() 被你的一个类的实例调用时所要产生的行为。本方法应该返回True或者False,取决于你想让它返回的值。

__dir__(self)

定义当 dir() 被你的一个类的实例调用时所要产生的行为。该方法应该返回一个属性的列表给用户,一般而言,实现 __dir__ 是不必要的,但是,如果你重新定义了__getattr__或__getattribute__(你将在下一节中看到)或者其它的动态生成属性,那么它对你的类的交互使用是至关重要的。

__sizeof__(self)

定义当 sys.getsizeof() 被你的一个类的实例调用时所要产生的行为。该方法应该以字节为单位,返回你的对象的大小。这通常对于以C扩展的形式实现的Python类更加有意义,其有助于理解这些扩展。

我们几乎完成了对这些枯燥的魔法方法(并且没有实例)的指导。现在,我们已经提及到了一些较基本的魔法方法,到了该转移到更高级内容的时候了。

属性访问控制

很多用过其它语言的人抱怨Python缺乏对类真正的封装(比如没办法定义private属性和public的getter和settter)。但这不是真的啊:真相是Python通过“魔法”实现了大量的封装,而不是使用明确的方法或字段修饰符。看一下吧:

__getattr__(self, name)

你可以定义如何处理用户试图访问一个不存在(不存在或还没创建)属性的行为。这对于捕获或者重定向一般的拼写错误非常有用,给出访问了不能访问的属性的警告(如果你愿意,你还可以推断并返回那个属性。),或者巧妙地处理一个AttributeError异常。它只有在一个不存在的属性被访问的情况下才被调用,然而,这并不是一个真正封装的方案。

__setattr__(self, name, value)

与__getattr__不同,__setattr__是一个真正的封装方案。它允许你定义当给一个存在或不存在的属性赋值时的行为,意味着对任何属性值的改变你都可以定义一个规则。可是,你得小心使用__setattr__,在这个清单结尾的例子会向你说明。

__delattr__

它与__setattr__非常像, 只不过是用来删除而不是设置属性。 __detattr__需要预防措施,就像setattr一样,当被调用时可能会引起无限递归(当__delattr__已经实现时,调用 del self.name 就会引起无限的递归)。

__getattribute__(self, name)

__getattribute__相当适合它的同伴__setattr__和__delattr__.但我却不建议你使用它。__getattribute__只有在新风格的类中才会被使用(所有的新风格类在Python最新的版本中,在老版本中,你可以子类化object来获得一个新风格类。它允许你定义一条规则来处理无论什么时候属性值被访问时的行为。比如类似于由于其它的伙伴犯错而引起的无限递归(这时你就可以调用基类的__getattribute__方法来阻止它)。它也避免了对__getattr__的依赖,当__getattribute__方法已经实现的时候,__getattr__只有在__getattribute__被明确的调用或抛出一个AttributeError异常的时候才会被调用。这个方法能被使用(毕竟,这是你的选择),但是我不推荐它,因为它很少使用并且运行的时候很难保证没有BUG。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/cb1b2f78dd9df2088d69413cabe7ac94.html