Python魔术方法教程描述了Python魔术方法是什么并展示了如何使用它们。在本教程中,我们介绍了一些常见的魔法方法。
Python魔术方法
Python魔术方法是为我们的自定义类添加功能的特殊方法。它们被双下划线包围(例如__add__())。
Python中有很多神奇的方法。它们中的大多数用于非常特殊的情况。我们将提及一些更流行的方法。
__add__方法
__add__
方法用于实现加法运算。在Python中,数字不是原始字面量而是对象。num+4
表达式等同于num.__add__(4)
。
#!/usr/bin/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'})
我们创建了两个简单的字典。
print(a + b)
我们添加两个字典。
$ ./add_dict.py {'de': 'Germany', 'sk': 'Slovakia'}
__init__和__str__方法
__init__
方法用于初始化对象。该方法用于实现对象的构造函数。__str__
提供对象的人类可读输出。
#!/usr/bin/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
调用。当计算返回对象的表达式时,它在Pythonshell上使用。
__str__
用于提供对象的人类可读版本,__repr__
用于提供对象的完整表示。后者的输出也更适合开发者。
如果缺少__str__
实现,则使用__repr__
方法作为回退。
def __repr__(self): return '<{0}.{1} object at {2}>'.format( self.__module__, type(self).__name__, hex(id(self)))
对象的__repr__
方法的默认实现类似于上面的代码。
#!/usr/bin/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__
方法定义项目访问([])运算符。
#!/usr/bin/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__
实现了索引操作。
print(deck[0])
我们拿到了牌组的第一张牌。这调用了__getitem__
。
print(len(deck))
这会调用__len__
方法。
$ ./french_deck.py Card(suit='heart', rank='2') 52 Card(suit='diamond', rank='A')
__int__和__index__方法
调用__int__
方法实现内置的int
函数。__index__
方法实现对象在切片表达式中使用时类型转换为int,内置hex
、oct
、bin
函数。
#!/usr/bin/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__
实现了>
运算符。
#!/usr/bin/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魔术方法实现了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')
我们将小袋与比较运算符进行比较。
二维向量示例
在下面的例子中,我们介绍了一些其他的魔术方法,包括__sub__
、__mul__
和__abs__
。
#!/usr/bin/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
在本教程中,我们使用了Python魔法方法。
列出所有Python教程。