
Python 中的魔法方法是一个方法集合,它自动与语言中的每个类定义相关联。如果你创建了自己的类,你可以覆盖一个或多个标准的魔法方法来定制它们的行为。Python 中有许多神奇的方法,我们在本教程的末尾列出了它们的表格。现在,我们想看看一些更常用的魔法方法,它们在日常编程中很有用。魔法可以用来定制你的对象如何被表示为字符串,控制在获取和设置过程中如何访问对象的属性,检查是否相等,以及使一个对象像函数一样可以被调用。
字符串表示法
我们要学习的前两个神奇的方法是 Python 用来生成对象的字符串表示法。一个叫做**__str__,另一个叫做__repr__** 。函数**__str__用于输出对象的一个用户友好的字符串描述,通常是为了显示给用户。__repr__函数更多的是用于软件的开发者。它输出一个可以用于调试的字符串,所以它被用来显示大量的详细信息。这些函数以各种方式在一个对象上被调用。当你调用print()函数并传入对象时,或者当你使用__str__或__repr__**铸造函数时,这些方法将被调用。
__str__和__repr__
class Book():
def __init__(self, title, author, price):
super().__init__()
self.title = title
self.author = author
self.price = price
def __str__(self):
return f'{self.title} by {self.author}, costs {self.price}'
def __repr__(self):
return f'title={self.title},author={self.author},price={self.price}'
book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)
print(book1)
print(book2)
print(str(book1))
print(repr(book2))
Python Crash Course by Eric Matthes, costs 23.99
Serious Python by Julien Danjou, costs 25.43
Python Crash Course by Eric Matthes, costs 23.99
title=Serious Python,author=Julien Danjou,price=25.43
等价和比较
通过使用平等和比较的魔法方法,我们可以给对象以相互比较的能力。当你的对象与另一个对象比较时,名为eq的魔法方法会被调用。下面的代码还实现了大于或等于魔法方法和小于魔法方法。
_eq__ __ge__ __lt__
class Book():
def __init__(self, title, author, price):
super().__init__()
self.title = title
self.author = author
self.price = price
def __eq__(self, value):
if not isinstance(value, Book):
raise ValueError('Can't compare book to non-book type')
return (self.title == value.title and
self.author == value.author and
self.price == value.price)
def __ge__(self, value):
if not isinstance(value, Book):
raise ValueError('Can't compare book to non-book type')
return self.price >= value.price
def __lt__(self, value):
if not isinstance(value, Book):
raise ValueError('Can't compare book to non-book type')
return self.price < value.price
book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)
book3 = Book('Automate the Boring Stuff with Python', 'Al Sweigart ', 26.99)
book4 = Book('Python for Kids', 'Jason Briggs', 19.79)
# Check for equality
print(book1 == book3)
print(book1 == book2)
print(book3 == book3)
# Check for greater and lesser value
print(book2 >= book1)
print(book2 < book1)
print(book3 >= book2)
# Sorting books
books = [book1, book3, book2, book4]
books.sort()
print([book.title for book in books])
False
False
True
True
False
True
['Python for Kids', 'Python Crash Course', 'Serious Python', 'Automate the Boring Stuff with Python']
属性访问
Python 的魔法方法也给了你对如何访问一个对象的属性的完全控制。一个类可以定义方法,在任何时候设置或检索一个属性时都可以拦截这个过程。我们在本节中要看的方法如下。
- __getattribute__当一个属性被检索时被调用。注意你不能直接访问 attr 名称,否则会产生一个递归循环。
- __setattr__当一个属性值被设置时被调用。不要在这里直接设置 attr,否则一个递归循环会导致崩溃。
- 当 __getattribute__ 查询失败时调用**__getattr__**- 你可以用这个方法即时生成属性。
__getattribute__ __setattr__ __getattr__
class Book():
def __init__(self, title, author, price):
super().__init__()
self.title = title
self.author = author
self.price = price
self._discount = 0.1
def __str__(self):
return f'{self.title} by {self.author}, costs {self.price}'
def __getattribute__(self, name):
if (name == 'price'):
price = super().__getattribute__('price')
discount = super().__getattribute__('_discount')
return price - (price * discount)
return super().__getattribute__(name)
def __setattr__(self, name, value):
if (name == 'price'):
if type(value) is not float:
raise ValueError('The "price" attribute must be a float')
return super().__setattr__(name, value)
def __getattr__(self, name):
return name + ' is not here!'
book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)
book1.price = 37.95
print(book1)
book2.price = float(40)
print(book2)
print(book1.randomprop)
Python Crash Course by Eric Matthes, costs 34.155
Serious Python by Julien Danjou, costs 36.0
randomprop is not here!
使一个对象可被调用
__call__魔法方法有一个有趣的能力,可以使一个对象可被调用,就像你在 Python 中调用其他函数一样。
class Book():
def __init__(self, title, author, price):
super().__init__()
self.title = title
self.author = author
self.price = price
def __str__(self):
return f'{self.title} by {self.author}, costs {self.price}'
def __call__(self, title, author, price):
self.title = title
self.author = author
self.price = price
book1 = Book('Python Crash Course', 'Eric Matthes', 23.99)
book2 = Book('Serious Python', 'Julien Danjou', 25.43)
print(book1)
book1('Learning Python', 'Mark Lutz', 44.94)
print(book1)
Python Crash Course by Eric Matthes, costs 23.99
Learning Python by Mark Lutz, costs 44.94
Python魔法方法参考
| 初始化和构造 | 它的作用 |
|---|
| __new__(cls, other) | 允许我们通过__new__魔法方法覆盖任何对象的新建步骤。 |
| __init__(self, other) | 当一个对象被创建时,通过调用对象的__init__方法来初始化它。 |
| __del__(self) | __del__是一个析构器方法,当对象的所有引用被删除时,即当一个对象被垃圾回收时,它就被调用。 |
| 单元运算符和函数 | 它的作用 |
|---|
| __pos__(self) | 实现单数正数的行为(例如:+some_object)。 |
| __neg__(self) | 当单数**-**运算符在我们的对象上被调用时,执行行为。 |
| __abs__(self) | 被内置的abs()函数调用。它从一个数字中去掉负号 (如果它是负的)。 |
| __invert__(self) | 使用~运算符。它是一个 "反转 "或 "补数 "的操作,输入数据的所有位都被反转。 |
| __round__(self,n) | 实现round()函数的行为。返回一个指定数字的四舍五入版本的浮点数。 |
| 返回一个四舍五入的浮点数。 | 执行内置的math.floor()函数。 |
| 返回指定数字的四舍五入版本的浮点数。 | ceil()返回 x 的最高值,即不小于 x 的最小整数。 |
| __trunc__(self) | 去掉任何小数,就是math.trunc()的作用。 |
| 增强的赋值 | 它的作用是什么? |
|---|
| __iadd__(self, other) | 用赋值做加法:a +=b |
| __isub__(self, other) | 带有赋值的减法:a -=b |
| __imul__(self, other) | 带有赋值的乘法:a *=b |
| 整数除法: a *=b | 整数除法,赋值:a //=b |
| __idiv__(self, other) | 带有赋值的除法:a /=b |
| 赋值:a /=b __itruediv__(self, other) | 带赋值的真除法 |
| __imod__(self, other) | 带赋值的模数:a%=b |
| 赋值:a%=b __ipow__(self, other) | 带赋值的指数:a **=b |
| 左移__(self, other) | 左位移位,赋值:a<<=b |
| __irshift__(self, other) | 右位移位,带有赋值:a >>=b |
| __iand__(self, other) | 带有赋值的位数和:a&=b |
| 顺序__(self, other) | 位数OR,赋值为:**a | =b** |
| 赋值为:a | =b。 | 位数XOR,赋值为:a ^=b |
| 类型转换 | 它的作用是什么? |
|---|
| __int__(self) | **int()**方法将一个类型转换为一个 int。 |
| __float__(self) | float() 方法将一个类型转换为 float。 |
| 方法将一个类型转换为复数。 | compound() 方法将一个类型转换为复数。 |
| 方法将一个类型转换为复数。 | oct() 方法将一个类型转换为八进制。 |
| __hex__(self) | hex() 方法将一个类型转换为十六进制。 |
| __index__(self) | 当对象在分片表达式中使用时,执行类型转换为int。 |
| __trunc__(self) | 从数学中获得调用。**trunc()**方法 |
| 字符串魔法方法 | 它的作用 |
|---|
| __str__(self) | str()方法,返回一个类型的字符串表示。 |
| __repr__(self) | repr()方法返回一个类型的机器可读表示。 |
| 方法返回类型的机器可读表示法。 | unicode()方法返回一个类型的unicode字符串。 |
| __format__(self, formatstr) | string.format()方法,返回一个新的字符串样式。 |
| 方法返回一个新的字符串样式。 | hash()方法返回一个整数。 |
| 使用__nonzero__(self) | bool() 方法,返回真或假。 |
| __dir__(self) | dir()方法,返回一个类的属性列表。 |
| __sizeof__(self) | sys.getsizeof()方法,返回一个对象的大小。 |
| 属性魔法方法 | 它的作用 |
|---|
| __getattr__(self, name) | 当访问一个不存在的类的属性时被调用。 |
| __setattr__(self, name, value) | 当给一个类的属性赋值时被调用。 |
| 当删除一个类的属性时,调用__delattr__(self, name) | 当删除一个类的属性时被调用。 |
| 操作符魔法方法 | 它的作用 |
|---|
| __add__(self, other) | 使用**+**操作符进行添加操作。 |
| __sub__(self, other) | 使用**-**运算符进行减法运算 |
| __mul__(self, other**)** | 使用*****运算符进行乘法运算 |
| 使用运算符**__floordiv__(self, other)** | 地面除法操作,使用**//**操作符 |
| __div__(self, other) | 除法运算,使用**/**操作符 |
| __mod__(self, other) | 使用**%**运算符进行模数运算 |
| __pow__(self, other[, modulo]) | 使用******运算符来计算功率 |
| __lt__(self, other) | 使用**<**操作符进行比较 |
| __le__(self, other) | 使用**<=**操作符进行比较 |
| __eq__(self, other) | 使用**==**运算符进行比较 |
| 使用__ne__(self, other) | 使用**!=**操作符进行比较 |
| __ge__(self, other) | 使用**>=**运算符进行比较 |