{% raw %}

Python 魔术方法

原文: http://zetcode.com/python/magicmethods/

Python 魔术方法教程描述了什么是 Python 魔术方法,并说明了如何使用它们。 在本教程中,我们介绍了一些常见的魔术方法。

Python 魔术方法

Python 魔术方法是为我们的自定义类添加功能的特殊方法。 它们被双下划线包围(例如__add __())。

Python 中有许多魔术方法。 它们中的大多数用于非常特殊的情况。 我们将提到一些更流行的方法。

__add__方法

__add__()方法用于实现加法运算。 在 Python 中,数字不是原始字面值,而是对象。 num + 4表达式等效于num.__add__(4)

add_dict.py

  1. #!/usr/bin/env python
  2. class MyDict(dict):
  3. def __add__(self, other):
  4. self.update(other)
  5. return MyDict(self)
  6. a = MyDict({'de': 'Germany'})
  7. b = MyDict({'sk': 'Slovakia'})
  8. print(a + b)

在示例中,我们有一个自定义字典,该字典使用__add__()实现加法运算。

  1. class MyDict(dict):
  2. def __add__(self, other):
  3. self.update(other)
  4. return MyDict(self)

自定义字典继承自内置dict__add__()方法与update()方法添加两个字典,并返回新创建的字典。

  1. a = MyDict({'de': 'Germany'})
  2. b = MyDict({'sk': 'Slovakia'})

我们创建两个简单的字典。

  1. print(a + b)

我们添加两个字典。

  1. $ ./add_dict.py
  2. {'de': 'Germany', 'sk': 'Slovakia'}

这是输出。

__init____str__方法

__init__()方法用于初始化对象。 此方法用于实现对象的构造器。 __str__()提供了对象可读的输出。

init_str.py

  1. #!/usr/bin/env python
  2. class Person:
  3. def __init__(self, name, occupation):
  4. self.name = name
  5. self.occupation = occupation
  6. def __str__(self):
  7. return f'{self.name} is a {self.occupation}'
  8. p = Person('John Doe', 'gardener')
  9. print(p)

在示例中,我们有一个Person类,具有两个属性:nameoccupation

  1. def __init__(self, name, occupation):
  2. self.name = name
  3. self.occupation = occupation

__init__()方法中,我们将实例变量设置为传递给构造器的值。

  1. def __str__(self):
  2. return f'{self.name} is a {self.occupation}'

__str__()方法可以很好地输出对象。

  1. $ ./init_str.py
  2. John Doe is a gardener

这是输出。

__repr__方法

__repr__()方法由内置函数repr()调用。 当它求值返回对象的表达式时,在 Python shell 上使用它。

__str__()用于提供对象的人类可读版本,__repr__()用于提供对象的完整表示。 后者的输出也更适合开发者。

如果缺少__str__()实现,则将__repr__()方法用作后备。

  1. def __repr__(self):
  2. return '<{0}.{1} object at {2}>'.format(
  3. self.__module__, type(self).__name__, hex(id(self)))

对象的__repr__()方法的默认实现类似于上面的代码。

repr_ex.py

  1. #!/usr/bin/env python
  2. class Person:
  3. def __init__(self, name, occupation):
  4. self.name = name
  5. self.occupation = occupation
  6. def __str__(self):
  7. return f'{self.name} is a {self.occupation}'
  8. def __repr__(self):
  9. return f'Person{{name: {self.name}, occupation: {self.occupation}}}'
  10. p = Person('John Doe', 'gardener')
  11. print(p)
  12. print(repr(p))

该示例实现了__str__()__repr__()方法。

  1. $ ./repr_ex.py
  2. John Doe is a gardener
  3. Person{name: John Doe, occupation: gardener}

这是输出。

__len____getitem__方法

__len__()方法返回容器的长度。 当我们在对象上使用内置的len()方法时,将调用该方法。 __getitem__()方法定义项目访问([])运算符。

french_deck.py

  1. #!/usr/bin/env python
  2. import collections
  3. from random import choice
  4. Card = collections.namedtuple('Card', ['suit', 'rank'])
  5. class FrenchDeck:
  6. ranks = [str(i) for i in range(2, 11)] + list('JQKA')
  7. suits = ["heart", "clubs", "spades", "diamond"]
  8. def __init__(self):
  9. self.total = [Card(suit, rank)
  10. for suit in self.suits for rank in self.ranks]
  11. def __len__(self):
  12. return len(self.total)
  13. def __getitem__(self, index):
  14. return self.total[index]
  15. deck = FrenchDeck()
  16. print(deck[0])
  17. print(len(deck))
  18. print(choice(deck))

该方法用于实现法语卡片组。

  1. Card = collections.namedtuple('Card', ['suit', 'rank'])

我们使用一个命名的元组来定义一个Card类。 namedtuple是用于创建元组类的工厂功能。 每张卡都有一套西装和一个等级。

  1. def __len__(self):
  2. return len(self.total)

__len__()方法返回卡座(52)中的卡数。

  1. def __getitem__(self, index):
  2. return self.total[index]

__getitem__()实现索引操作。

  1. print(deck[0])

我们得到卡组的第一张牌。 这称为__getitem__()

  1. print(len(deck))

这将调用__len__()方法。

  1. $ ./french_deck.py
  2. Card(suit='heart', rank='2')
  3. 52
  4. Card(suit='diamond', rank='A')

这是输出。

__int____index__方法

调用__int__()方法以实现内置的int()函数。 当在切片表达式中使用对象以及内置的hex()oct()bin()函数时,__index__()方法将类型转换为int

char_ex.py

  1. #!/usr/bin/env python
  2. class Char:
  3. def __init__(self, val):
  4. self.val = val
  5. def __int__(self):
  6. return ord(self.val)
  7. def __index__(self):
  8. return ord(self.val)
  9. c1 = Char('a')
  10. print(int(c1))
  11. print(hex(c1))
  12. print(bin(c1))
  13. print(oct(c1))

在示例中,我们创建一个自定义的Char类,该类实现了int()hex()bin()oct()函数。

  1. ./char_ex.py
  2. 97
  3. 0x61
  4. 0b1100001
  5. 0o141

这是输出。

__eq ____ lt____gt__方法

__eq__()实现了==运算符。 __lt__()实现了<运算符,__gt__()实现了>运算符。

pouch.py

  1. #!/usr/bin/env python
  2. import collections
  3. Coin = collections.namedtuple('coin', ['rank'])
  4. # a gold coin equals to two silver and six bronze coins
  5. class Pouch:
  6. def __init__(self):
  7. self.bag = []
  8. def add(self, coin):
  9. self.bag.append(coin)
  10. def __eq__(self, other):
  11. val1, val2 = self.__evaluate(other)
  12. if val1 == val2:
  13. return True
  14. else:
  15. return False
  16. def __lt__(self, other):
  17. val1, val2 = self.__evaluate(other)
  18. if val1 < val2:
  19. return True
  20. else:
  21. return False
  22. def __gt__(self, other):
  23. val1, val2 = self.__evaluate(other)
  24. if val1 > val2:
  25. return True
  26. else:
  27. return False
  28. def __str__(self):
  29. return str(self.bag)
  30. def __evaluate(self, other):
  31. val1 = 0
  32. val2 = 0
  33. for coin in self.bag:
  34. if coin.rank == 'g':
  35. val1 += 6
  36. if coin.rank == 's':
  37. val1 += 3
  38. if coin.rank == 'b':
  39. val1 += 1
  40. for coin in other.bag:
  41. if coin.rank == 'g':
  42. val2 += 6
  43. if coin.rank == 's':
  44. val2 += 3
  45. if coin.rank == 'b':
  46. val2 += 1
  47. return val1, val2
  48. pouch1 = Pouch()
  49. pouch1.add(Coin('g'))
  50. pouch1.add(Coin('g'))
  51. pouch1.add(Coin('s'))
  52. pouch2 = Pouch()
  53. pouch2.add(Coin('g'))
  54. pouch2.add(Coin('s'))
  55. pouch2.add(Coin('s'))
  56. pouch2.add(Coin('b'))
  57. pouch2.add(Coin('b'))
  58. pouch2.add(Coin('b'))
  59. print(pouch1)
  60. print(pouch2)
  61. if pouch1 == pouch2:
  62. print('Pouches have equal value')
  63. elif pouch1 > pouch2:
  64. print('Pouch 1 is more valueable than Pouch 2')
  65. else:
  66. print('Pouch 2 is more valueable than Pouch 1')

我们有一个可以容纳金,银和青铜硬币的小袋。 一枚金币等于两个银币和六个铜币。 在示例中,我们使用 Python 魔术方法为pouch对象实现了三个比较运算符。

  1. def __eq__(self, other):
  2. val1, val2 = self.__evaluate(other)
  3. if val1 == val2:
  4. return True
  5. else:
  6. return False

__eq__()方法中,我们首先求值两个小袋的值。 然后我们比较它们并返回布尔结果。

  1. def __evaluate(self, other):
  2. val1 = 0
  3. val2 = 0
  4. for coin in self.bag:
  5. if coin.rank == 'g':
  6. val1 += 6
  7. if coin.rank == 's':
  8. val1 += 3
  9. if coin.rank == 'b':
  10. val1 += 1
  11. for coin in other.bag:
  12. if coin.rank == 'g':
  13. val2 += 6
  14. if coin.rank == 's':
  15. val2 += 3
  16. if coin.rank == 'b':
  17. val2 += 1
  18. return val1, val2

__evaluate()方法计算两个袋的值。 它穿过小袋的硬币,并根据硬币的等级增加一个值。

  1. pouch1 = Pouch()
  2. pouch1.add(Coin('g'))
  3. pouch1.add(Coin('g'))
  4. pouch1.add(Coin('s'))

我们创建第一个袋,并在其中添加三个硬币。

  1. if pouch1 == pouch2:
  2. print('Pouches have equal value')
  3. elif pouch1 > pouch2:
  4. print('Pouch 1 is more valueable than Pouch 2')
  5. else:
  6. print('Pouch 2 is more valueable than Pouch 1')

我们将小袋与比较运算符进行比较。

2D 向量示例

在下面的示例中,我们介绍了几种其他魔术方法,包括__sub__()__mul__()__abs__()

vector.py

  1. #!/usr/bin/env python
  2. import math
  3. class Vec2D:
  4. def __init__(self, x, y):
  5. self.x = x
  6. self.y = y
  7. def __add__(self, other):
  8. return Vec2D(self.x + other.x, self.y + other.y)
  9. def __sub__(self, other):
  10. return Vec2D(self.x - other.x, self.y - other.y)
  11. def __mul__(self, other):
  12. return self.x * other.x + self.y * other.y
  13. def __abs__(self):
  14. return math.sqrt(self.x ** 2 + self.y ** 2)
  15. def __eq__(self, other):
  16. return self.x == other.x and self.y == other.y
  17. def __str__(self):
  18. return f'({self.x}, {self.y})'
  19. def __ne__(self, other):
  20. return not self.__eq__(other)
  21. u = Vec2D(0, 1)
  22. v = Vec2D(2, 3)
  23. w = Vec2D(-1, 1)
  24. a = u + v
  25. print(a)
  26. print(a == w)
  27. a = u - v
  28. print(a)
  29. a = u * v
  30. print(a)
  31. print(abs(u))
  32. print(u == v)
  33. print(u != v)

在示例中,我们有一个Vec2D类。 我们可以比较,加,减和乘向量。 我们还可以计算向量的长度。

  1. $ ./vector.py
  2. (2, 4)
  3. False
  4. (-2, -2)
  5. 3
  6. 1.0
  7. False
  8. True

这是输出。

在本教程中,我们使用了 Python 魔术方法。

您可能也对以下相关教程感兴趣: Python 字符串Python Jinja 教程Python 教程,或列出所有 Python 教程

{% endraw %}