创建类magic method:
__new__:创建一个对象时真正第一个调用的方法,该方法为类方法,会创建一个对象并吧其与传入参数一并交给__init__
__init__:初始化对象,对__new__创建的对象进行一些初始化操作
__del__:在对象不再被使用的时候自动进行进行调用,可以执行一些善后工作,但是由于不知道该方法会在什么时候被执行,所以其可控性差,所以不建议被使用
比较类migic method:
__cmp__:可以定义所有比较,当大于时返回正数,小于时返回负数,等于时返回0
__eq__:定义等于==
__ne__:定义不等!=
__lt__:定义小于<
__gt__:定义大于>
__le__:定义小于等于<=
__ge__:定义大于等于>=
Numeric magic methods:(具体翻译不明确,运算符?)
一元运算符:
__pos__(self):相当于+
__neg__(self):相当于-
__abs__(self):使用abs()方法时调用
__invert__(self):反转,即NOT,比如NOT 0001 = 1000
Normal arithmetic operators:(一般常用运算符)
__add__(self, other):实现加法,跟__pos__的差别?
__sub__(self, other):实现减法
__mul__(self, other):实现乘法
__floordiv__(self, other):实现了整数的除法使用/ /操作符。。。(有道翻译)
__div__(self, other):实现除法使用/操作符号(跟上面的区别是返回结果不是整数)
__truediv__(self, other):实现真正的除法?只有当从__future__导入division的时候才会工作
__mod__(self, other):实现取余通过%操作符
__divmod__(self, other):实现长除法(?)使用divmod()内置函数的时候
__pow__(self, other):实现指数操作使用**操作符
__lshift__(self, other):实现左移操作使用<<操作符
__rshift__(self, other):实现右移操作使用>>操作符
__and__(self, other):实现与操作使用&操作符
__or__(self, other):实现或操作使用|操作符
__xor__(self, other):实现xor操作使用^操作符
以上所有方法前面加上r即是自身作为第二个操作数时的实现,如__radd__就是当other+me时调用,而__add__是me+other时调用,一般时候这两个实现是一样的,所以只要其中一个调用另外一个方法就行
Augmented assignment(累加累减之流):
__iadd__(self, other):定义i++
__isub__(self, other):定义i--
__imul__(self, other):定义i**
以此类推,以上的一般运算都有相应的累计运算
Type conversion magic methods:(用于类型转换)
__int__(self):__float__(self):__long__(self):分别对应int(), float(), long()方法作用于该对象上时返回值,注意,只能返回对应的类型
__complex__(self):复杂?
__oct__(self):八进制
__hex__(self):十六进制
__index__(self):当对象是被应用在切片表达式中时,实现整形强制转换,如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 __index__(博主表示难以理解,貌似是用在列表中的?没有找到实际的例子)
__trunc__(self):当调用math.trunc(self)时得到调用,通常返回一个long型
__coerce__(self):
表现你的类¶
如果有一个字符串来表示一个类将会非常有用。在Python中,有很多方法可以实现类定义内置的一些函数的返回值。 __str__(self) 定义当 str() 调用的时候的返回值 __repr__(self) 定义 repr() 被调用的时候的返回值。 str() 和 repr() 的主要区别在于 repr() 返回的是机器可读的输出,而 str() 返回的是人类可读的。 __unicode__(self) 定义当 unicode() 调用的时候的返回值。 unicode() 和 str() 很相似,但是返回的是unicode字符串。注意,如a果对你的类调用 str() 然而你只定义了 __unicode__() ,那么将不会工作。你应该定义 __str__() 来确保调用时能返回正确的值。
__hash__(self) 定义当 hash() 调用的时候的返回值,它返回一个整形,用来在字典中进行快速比较 __nonzero__(self) 定义当 bool() 调用的时候的返回值。本方法应该返回True或者False,取决于你想让它返回的值。
控制属性访问¶
许多从其他语言转到Python的人会抱怨它缺乏类的真正封装。(没有办法定义私有变量,然后定义公共的getter和setter)。Python其实可以通过魔术方法来完成封装。我们来看一下:
__getattr__(self, name) 你可以定义当用户试图获取一个不存在的属性时的行为。这适用于对普通拼写错误的获取和重定向,对获取一些不建议的属性时候给出警告(如果你愿意你也可以计算并且给出一个值)或者处理一个 AttributeError 。只有当调用不存在的属性的时候会被返回。然而,这不是一个封装的解决方案。 __setattr__(self, name, value) 与 __getattr__ 不同, __setattr__ 是一个封装的解决方案。无论属性是否存在,它都允许你定义对对属性的赋值行为,以为这你可以对属性的值进行个性定制。但是你必须对使用 __setattr__ 特别小心。之后我们会详细阐述。 __delattr__ 与 __setattr__ 相同,但是功能是删除一个属性而不是设置他们。注意与 __setattr__ 相同,防止无限递归现象发生。(在实现 __delattr__ 的时候调用 del self.name 即会发生) __getattribute__(self, name) __getattribute__ 与它的同伴 __setattr__ 和 __delattr__ 配合非常好。但是我不建议使用它。只有在新类型类定义中才能使用 __getattribute__ (在最新版本Python中所有的类都是新类型,在老版本中你可以通过继承 object 来制作一个新类。这样你可以定义一个属性值的访问规则。有时也会产生一些帝归现象。(这时候你可以调用基类的 __getattribute__ 方法来防止此现象的发生。)它可以消除对 __getattr__ 的使用,如果它被明确调用或者一个 AttributeError 被抛出,那么当实现 __getattribute__ 之后才能被调用。此方法是否被使用其实最终取决于你的选择。)我不建议使用它因为它的使用几率较小(我们在取得一个值而不是设置一个值的时候有特殊的行为是非常罕见的。)而且它不能避免会出现bug。
在进行属性访问控制定义的时候你可能会很容易的引起一个错误。考虑下面的例子。
def __setattr__(self, name, value):
self.name = value
#每当属性被赋值的时候, ``__setattr__()`` 会被调用,这样就造成了递归调用。
#这意味这会调用 ``self.__setattr__('name', value)`` ,每次方法会调用自己。这样会造成程序崩溃。
def __setattr__(self, name, value):
self.__dict__[name] = value #给类中的属性名分配值
#定制特有属性
Python的魔术方法非常强大,然而随之而来的则是责任。了解正确的方法去使用非常重要。
所以我们对于定制属性访问权限了解了多少呢。它不应该被轻易的使用。实际上,它非常强大。但是它存在的原因是:Python 不会试图将一些不好的东西变得不可能,而是让它们难以实现。自由是至高无上的,所以你可以做任何你想做的。一下是一个特别的属性控制的例子(我们使用 super 因为不是所有的类都有 __dict__ 属性):
class AccessCounter:
'''一个包含计数器的控制权限的类每当值被改变时计数器会加一'''
def __init__(self, val):
super(AccessCounter, self).__setattr__('counter', 0)
super(AccessCounter, self).__setattr__('value', val)
def __setattr__(self, name, value):
if name == 'value':
super(AccessCounter, self).__setattr__('counter', self.counter + 1)
#如果你不想让其他属性被访问的话,那么可以抛出 AttributeError(name) 异常
super(AccessCounter, self).__setattr__(name, value)
def __delattr__(self, name):
if name == 'value':
super(AccessCounter, self).__setattr__('counter', self.counter + 1)
super(AccessCounter, self).__delattr__(name)]