Python 魔术方法
Python 魔术方法 教程描述了什么是 Python 魔术方法,并说明了如何使用它们。 在本教程中,我们介绍了一些常见的魔术方法。
Python 魔术方法
Python 魔术方法是为我们的自定义类添加功能的特殊方法。 它们被双下划线包围(例如__add __()
)。
Python 中有许多魔术方法。 它们中的大多数用于非常特殊的情况。 我们将提到一些更流行的方法。
__add__
方法
__add__()
方法用于实现加法运算。 在 Python 中,数字不是原始文字,而是对象。 num + 4
表达式等效于num.__add__(4)
。
add_dict.py
| #!/usr/bin/env python
class MyDict(dict):
def __add__(self, other):
self.update(other)
return MyDict(self)
a = MyDict({'de': 'Germany'})
b = MyDict({'sk': 'Slovakia'})
print(a + b)
|
在示例中,我们有一个自定义词典,该词典使用__add__()
实现加法运算。
| class MyDict(dict):
def __add__(self, other):
self.update(other)
return MyDict(self)
|
自定义词典继承自内置dict
。 __add__()
方法与update()
方法添加两个字典,并返回新创建的字典。
| a = MyDict({'de': 'Germany'})
b = MyDict({'sk': 'Slovakia'})
|
我们创建两个简单的字典。
我们添加两个字典。
| $ ./add_dict.py
{'de': 'Germany', 'sk': 'Slovakia'}
|
这是输出。
__init__
和__str__
方法
__init__()
方法用于初始化对象。 此方法用于实现对象的构造函数。 __str__()
提供了对象可读的输出。
init_str.py
| #!/usr/bin/env python
class Person:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
def __str__(self):
return f'{self.name} is a {self.occupation}'
p = Person('John Doe', 'gardener')
print(p)
|
在示例中,我们有一个 Person 类,具有两个属性:name
和occupation
。
| def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
|
在__init__()
方法中,我们将实例变量设置为传递给构造函数的值。
| def __str__(self):
return f'{self.name} is a {self.occupation}'
|
__str__()
方法可以很好地输出对象。
| $ ./init_str.py
John Doe is a gardener
|
这是输出。
__repr__
方法
__repr__()
方法由内置函数repr()
调用。 当它评估返回对象的表达式时,在 Python shell 上使用它。
__str__()
用于提供对象的人类可读版本,__repr__()
用于提供对象的完整表示。 后者的输出也更适合开发人员。
如果缺少__str__()
实现,则将__repr__()
方法用作后备。
| def __repr__(self):
return '<{0}.{1} object at {2}>'.format(
self.__module__, type(self).__name__, hex(id(self)))
|
对象的__repr__()
方法的默认实现类似于上面的代码。
repr_ex.py
| #!/usr/bin/env python
class Person:
def __init__(self, name, occupation):
self.name = name
self.occupation = occupation
def __str__(self):
return f'{self.name} is a {self.occupation}'
def __repr__(self):
return f'Person(name: {self.name}, occupation: {self.occupation})'
p = Person('John Doe', 'gardener')
print(p)
print(repr(p))
|
该示例实现了__str__()
和__repr__()
方法。
| $ ./repr_ex.py
John Doe is a gardener
Person{name: John Doe, occupation: gardener}
|
这是输出。
__len__
和__getitem__
方法
__len__()
方法返回容器的长度。 当我们在对象上使用内置的len()
方法时,将调用该方法。 __getitem__()
方法定义项目访问([])运算符。
french_deck.py
| #!/usr/bin/env python
import collections
from random import choice
Card = collections.namedtuple('Card', ['suit', 'rank'])
class FrenchDeck:
ranks = [str(i) for i in range(2, 11)] + list('JQKA')
suits = ["heart", "clubs", "spades", "diamond"]
def __init__(self):
self.total = [Card(suit, rank)
for suit in self.suits for rank in self.ranks]
def __len__(self):
return len(self.total)
def __getitem__(self, index):
return self.total[index]
deck = FrenchDeck()
print(deck[0])
print(len(deck))
print(choice(deck))
|
该方法用于实现法语卡片组。
| Card = collections.namedtuple('Card', ['suit', 'rank'])
|
我们使用一个命名的元组来定义一个Card
类。 namedtuple
是用于创建元组类的工厂功能。 每张卡都有一套西装和一个等级。
| def __len__(self):
return len(self.total)
|
__len__()
方法返回卡座(52)中的卡数。
| def __getitem__(self, index):
return self.total[index]
|
__getitem__()
实现索引操作。
我们得到卡组的第一张牌。 这称为__getitem__()
。
这将调用__len__()
方法。
| $ ./french_deck.py
Card(suit='heart', rank='2')
52
Card(suit='diamond', rank='A')
|
这是输出。
__int__
和__index__
方法
调用__int__()
方法以实现内置的int()
功能。 当在切片表达式中使用对象以及内置的hex()
,oct()
和bin()
函数时,__index__()
方法将类型转换为 int。
char_ex.py
| #!/usr/bin/env python
class Char:
def __init__(self, val):
self.val = val
def __int__(self):
return ord(self.val)
def __index__(self):
return ord(self.val)
c1 = Char('a')
print(int(c1))
print(hex(c1))
print(bin(c1))
print(oct(c1))
|
在示例中,我们创建一个自定义的Char
类,该类实现了int()
,hex()
,bin()
和oct()
函数。
| ./char_ex.py
97
0x61
0b1100001
0o141
|
这是输出。
__eq __
,__ lt__
和__gt__
方法
__eq__()
实现了==
运算符。 __lt__()
实现了<
运算符,__gt__()
实现了>
运算符。
pouch.py
| #!/usr/bin/env python
import collections
Coin = collections.namedtuple('coin', ['rank'])
# a gold coin equals to two silver and six bronze coins
class Pouch:
def __init__(self):
self.bag = []
def add(self, coin):
self.bag.append(coin)
def __eq__(self, other):
val1, val2 = self.__evaluate(other)
if val1 == val2:
return True
else:
return False
def __lt__(self, other):
val1, val2 = self.__evaluate(other)
if val1 < val2:
return True
else:
return False
def __gt__(self, other):
val1, val2 = self.__evaluate(other)
if val1 > val2:
return True
else:
return False
def __str__(self):
return str(self.bag)
def __evaluate(self, other):
val1 = 0
val2 = 0
for coin in self.bag:
if coin.rank == 'g':
val1 += 6
if coin.rank == 's':
val1 += 3
if coin.rank == 'b':
val1 += 1
for coin in other.bag:
if coin.rank == 'g':
val2 += 6
if coin.rank == 's':
val2 += 3
if coin.rank == 'b':
val2 += 1
return val1, val2
pouch1 = Pouch()
pouch1.add(Coin('g'))
pouch1.add(Coin('g'))
pouch1.add(Coin('s'))
pouch2 = Pouch()
pouch2.add(Coin('g'))
pouch2.add(Coin('s'))
pouch2.add(Coin('s'))
pouch2.add(Coin('b'))
pouch2.add(Coin('b'))
pouch2.add(Coin('b'))
print(pouch1)
print(pouch2)
if pouch1 == pouch2:
print('Pouches have equal value')
elif pouch1 > pouch2:
print('Pouch 1 is more valueable than Pouch 2')
else:
print('Pouch 2 is more valueable than Pouch 1')
|
我们有一个可以容纳金,银和青铜硬币的小袋。 一枚金币等于两个银币和六个铜币。 在示例中,我们使用 Python magic 方法为 pouch 对象实现了三个比较运算符。
| def __eq__(self, other):
val1, val2 = self.__evaluate(other)
if val1 == val2:
return True
else:
return False
|
在__eq__()
方法中,我们首先评估两个小袋的值。 然后我们比较它们并返回布尔结果。
| def __evaluate(self, other):
val1 = 0
val2 = 0
for coin in self.bag:
if coin.rank == 'g':
val1 += 6
if coin.rank == 's':
val1 += 3
if coin.rank == 'b':
val1 += 1
for coin in other.bag:
if coin.rank == 'g':
val2 += 6
if coin.rank == 's':
val2 += 3
if coin.rank == 'b':
val2 += 1
return val1, val2
|
__evaluate()
方法计算两个袋的值。 它穿过小袋的硬币,并根据硬币的等级增加一个值。
| pouch1 = Pouch()
pouch1.add(Coin('g'))
pouch1.add(Coin('g'))
pouch1.add(Coin('s'))
|
我们创建第一个袋,并在其中添加三个硬币。
| if pouch1 == pouch2:
print('Pouches have equal value')
elif pouch1 > pouch2:
print('Pouch 1 is more valueable than Pouch 2')
else:
print('Pouch 2 is more valueable than Pouch 1')
|
我们将小袋与比较运算符进行比较。
2D 向量示例
在下面的示例中,我们介绍了几种其他魔术方法,包括__sub__()
,__mul__()
和__abs__()
。
vector.py
| #!/usr/bin/env python
import math
class Vec2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vec2D(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vec2D(self.x - other.x, self.y - other.y)
def __mul__(self, other):
return self.x * other.x + self.y * other.y
def __abs__(self):
return math.sqrt(self.x ** 2 + self.y ** 2)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __str__(self):
return f'({self.x}, {self.y})'
def __ne__(self, other):
return not self.__eq__(other)
u = Vec2D(0, 1)
v = Vec2D(2, 3)
w = Vec2D(-1, 1)
a = u + v
print(a)
print(a == w)
a = u - v
print(a)
a = u * v
print(a)
print(abs(u))
print(u == v)
print(u != v)
|
在示例中,我们有一个Vec2D
类。 我们可以比较,加,减和乘向量。 我们还可以计算向量的长度。
| $ ./vector.py
(2, 4)
False
(-2, -2)
3
1.0
False
True
|
这是输出。