魔术方法
[TOC]
魔术方法
"魔术方法"指被用于重载
Python
的操作符或内置方法每个魔术方法都有特定的目的, 当特定语法出现时, 它作为执行的钩子(钩子是指在特定事件发生时, 能够为响应事件而调用的代码或函数, 回调函数算是钩子的一种)
魔术方法需要特定的函数名称和签名, 然后会在特定情况下被调用
创建与销毁
___init__方法
在创建实例后会立即执行对象的
__init__
方法该方法必须接受一个位置参数(self), 然后可以接受任意数量的可选参数
该方法并没有创建新对象(该操作由
__new__
完成), 只在为创建后的对象提供初始化数据__init__
方法并不返回任何值, 如果使用return
语句返回值则会导致TypeError
错误import sys print("Python版本信息: ", sys.version) class Person(object): def __init__(self, name='name'): self.name = name return name pass p = Person()
输出
D:\Software\Installed\Python\Python36\python.exe D:/workspace/Pycharm/PurePythonProject/Test07.py Python版本信息: 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] Traceback (most recent call last): File "D:/workspace/Pycharm/PurePythonProject/Test07.py", line 13, in <module> p = Person() TypeError: __init__() should return None, not 'str' Process finished with exit code 1
__new__方法
__new__
方法在__init__
之前执行, 用于创建类的实例,__new__
方法才是实际上创建并返回实例的方法__new__
永远是静态的简单实例
import sys print("Python版本信息: ", sys.version) class Person(object): def __new__(cls, *args, **kwargs): instance = super(Person, cls).__new__(cls) print('Person.__new__(A): ', kwargs) kwargs['name'] = 'Snow' kwargs['age'] = '20' print('Person.__new__(B): ', kwargs) instance.name = 'Go' return instance pass def __init__(self, *args, **kwargs): self.name = kwargs.get('name') print('Person.__init__: ', kwargs) pass pass class Teacher(Person): def __new__(cls, *args, **kwargs): instance = super(Teacher, cls).__new__(cls, *args, **kwargs) kwargs['salary'] = '3000' print('Teacher.__new__: ', kwargs) instance.name = 'Join' return instance pass def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.salary = kwargs.get('salary') print('Teacher.__init__: ', kwargs) pass p = Person(name='Hodor') print(p.name) print('\n', '*' * 50, '\n') t = Teacher(name='Hodor', salary='5000') print(t.name, t.salary)
输出
D:\Software\Installed\Python\Python36\python.exe D:/workspace/Pycharm/PurePythonProject/Test07.py Python版本信息: 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] Person.__new__(A): {'name': 'Hodor'} Person.__new__(B): {'name': 'Snow', 'age': '20'} Person.__init__: {'name': 'Hodor'} Hodor ************************************************** Person.__new__(A): {'name': 'Hodor', 'salary': '5000'} Person.__new__(B): {'name': 'Snow', 'salary': '5000', 'age': '20'} Teacher.__new__: {'name': 'Hodor', 'salary': '3000'} Person.__init__: {'name': 'Hodor', 'salary': '5000'} Teacher.__init__: {'name': 'Hodor', 'salary': '5000'} Hodor 5000 Process finished with exit code 0
大多数情况下,
__new__
方法的其他参数会被完整复制到__init__
方法中参数在调用构造函数时首先会被传递给
__new__
方法(由于先被调用)从上例可以看出, 参数在
__new__
方法中无法被修改
__del__方法
__del__
方法在对象被销毁时调用无论是直接删除或是由垃圾回收器进行销毁, 都会调用
__del__
方法
类型转换
在Python
中有很多用于将复杂对象转换为简单对象或常用数据类型的魔术方法.
__str__
该方法接受一个位置参数self
, 并在对象被传递给str
的构造函数时被调用, 然后返回一个字符串.
deepin@ThinkCentre:~/Desktop$ python3
Python 3.5.2+ (default, Nov 3 2016, 11:10:16)
[GCC 6.2.0 20161027] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class MyObject(object):
... def __str__(self):
... return "My Awesome Object!"
...
>>> str(MyObject())
'My Awesome Object!'
Python2
中有__unicode__
方法, 该方法在对象传递给unicode
的构造函数时被调用Python3
中有__bytes__
方法, 该方法在对象传递给bytes
的构造方法时被调用
__bool__
用来界定对象True
或False
.该类型的操作, 在Python3
中由__bool__
魔术方法处理, 在Python2
中由__nonzero__
魔术方法处理.
__int__, __float__, __complex__
某些情况下, 将复杂对象转换为基本类型的数字十分有价值. 如果一个对象定义了一个返回INT类型的__int__
方法, 那么该对象被传递给int的构造函数时, __int__
方法会被调用.
比较
对象在进行相等性测试(==
或!=
)或不等性测试(<
, <=
等)时进行比较, 这些操作符与Python中的魔术方法一一对应.
二元相等性
__eq__
__eq__
方法在对象使用==
操作符进行比较时被调用优先调用左侧对象
__eq__
方法要确保相等性检测始终可交换
如果被比较的两个对象中一个对象是另一个对象的直接子类, 将使用子类的
__eq__
方法
__ne__
__ne__
在使用!=
操作符时被调用如果没有定义
__ne__
方法, 那么Python会调用__eq__
方法, 并对结果取反
相对比较
__lt__
:<
__le__
:<=
__gt__
:>
__ge__
:>=
通常只需定义
__eq__
和__lt__
(或__gt__
), 那么所有6个比较操作都可以正常执行
__cmp__
__cmp__
方法是为对象定义相对比较的旧有(不推荐)方式接受
self
和other
两个参数, 如果self比other小, 返回负数; self比other大返回正整数; 相等时返回0__cmp__
在python2中被淘汰; 在python3中不可用
操作符重载
二元操作符
Python为每个操作符提供了三种重载方式.
普通方法(vanilla method): 表达式
x+y
与x.__add__(y)
匹配取反方法(reversemethod): 只有在第一个操作对象不提供对应方法并且操作对象类型不同(或返回NotImplemented)时才调用取反(操作符两边对象顺序交换). 定义该类魔法方法是在方法名称的开头加上r. 因此对于表达式
x+y
, 如果x没有定义__add__
方法, 则调用y.__radd__(x)
即席方法(in-place method): 此类操作符包括
+=
,*=
等, 定义此类方法, 只需在普通方法名加上i. 因此表达式x+=y
将会调用x.__iadd__(y)
操作符
方法
取反
即席
+
__add__
__radd__
__iadd__
-
__sub__
__rsub__
__isub__
*
__mul__
__rmul__
__imul__
/
__truediv__
__rtruediv__
__itruediv__
//
__floordiv__
__rfloordiv__
__ifloordiv__
%
__mod__
__rmod__
__imod__
**
__pow__
__rpow__
__ipow__
&
__and__
__rand__
__iand__
`
`
__or__
__ror__
__ior__
^
__xor__
__rxor__
__ixor__
<<
__lshift__
__rlshift__
__ilshift__
>>
__rshift__
__rrshift__
__irshift__
一元操作符
+(正):
__pos__
-(负):
__neg__
~(取反):
__invert__
重载常见方法
__len__
: 长度__repr__
: 用来确定该对象在Python交互式终端中的显示方式```python
代码
class TimeSpan(): def init(self, hours=0, minutes=0, seconds=0): self.hours = hours self.minutes = minutes self.seconds = seconds
def __repr__(self): return 'TimeSpan(hours=%d, minutes=%d, seconds=%d)' % (self.hours, self.minutes, self.seconds)
class TimeSpanWithoutRepr(): def init(self, hours=0, minutes=0, seconds=0): self.hours = hours self.minutes = minutes self.seconds = seconds
print(TimeSpan()) print(TimeSpanWithoutRepr())
输出
TimeSpan(hours=0, minutes=0, seconds=0)
```
__hash__
: 通过数字化表达式唯一标识对象.当一个对象传递给散列函数时, 调用其
__hash__
方法.该方法接受一个位置参数, 返回一个整形值, 该值可为负数.
如果一个对象定义了
__eq__
方法, 则__hash__
方法隐式地被赋值为None.常见用法: 用于字典的键值与set对象. 仅有可哈希化的对象可以最为字典的键值; 仅有可哈希的对象可以在set对象中存在.
__format__
: 该函数根据Python的格式化规范来格式化不同类型的对象.
最后更新于
这有帮助吗?