【翻译】5个 Python 类的未知技巧
翻译?
5 Unknown Tricks for Python Classes
Python 有许多强大的特性,在处理类时提供了极大的灵活性。 在这里,我将向你展示五个高级特性,它们可以帮助你编写更好的代码。
?
创建一个常量值 假设我们正在创建一个
Circle
类。 我们可能需要一种计算面积和一种计算周长的方法:class Circle():
def __init__(self, radius):
self.radius = radiusdef area(self):
return 3.14 * self.radius * self.radius def perimeter(self):
return 2 * 3.14 * self.radius
?
这个实现似乎可行,但是如果我们想将 pi 的值更改为更精确怎么办? 我们需要在两个地方更改它。 一个更好的主意是将 pi 的值保存在一个变量中:
class Circle():
def __init__(self, radius):
self.radius = radius
self.pi = 3.14def area(self):
return self.pi * self.radius * self.radius def perimeter(self):
return 2 * self.pi * self.radius
?
但是,现在任何人都可以更改 pi 的值。 这可不是什么好事:如果用户编写如下内容怎么办:
c = Circle(4)
c.pi = 5
?
这将破坏我们所有的功能! 显然,我们必须对此做些什么。 不幸的是,Python 不允许创建常量。 我们可以使用一个函数,该函数带有标签
@property
,并返回 pi。 这样,函数就可以像变量一样被调用而无需括号。class Circle():
def __init__(self, radius):
self.radius = radius@property
def pi(self):
return 3.14def area(self):
return self.pi * self.radius * self.radius def perimeter(self):
return 2 * self.pi * self.radius
?
现在 pi 的值不能被用户更改,它只存储在一个地方。
?
多个类构造函数 在 Python 中,类的构造函数是用
__init__
方法定义的。 不幸的是,不允许函数重载,因此我们只能定义一个这样的函数。 但是,有一种方法可以使用类似于类构造函数的方法。 这可以使用 @classmethod
标签来完成。?
例如,假设我们正在创建一个
Date
类 。 第一个构造函数是:class Date():
def __init__(self, day, month, year):
self.day = day
self.month = month
self.year = year
?
现在我们可能想要添加另一个构造函数,从
dd/mm/yyyy
格式的字符串中获取日期。 我们可以在 Date 类中创建一个类方法:@classmethod
def fromString(obj, s):
day = int(s[:2])
month = int(s[3:5])
year = int(s[6:])
return obj(day, month, year) # Return a new object
?
现在我们可以通过调用 fromString 方法创建一个新的 Date 对象:
d = Date.fromString("21/07/2020")
print(d.day, d.month, d.year)
Output:
21 7 2020
?
创建枚举 假设你的程序中有一个代表星期几的变量。 你可能会将它表示为一个整数,例如星期一是 1,星期二是 2 等等。但是,这不是最佳的,因为你必须记住你是从 0 开始还是从 1 开始。
?
此外,当你打印该值时,它将只是一个整数,因此你需要一个函数将其转换为正确的名称。
?
幸运的是,我们可以使用 enum 库中的 Enum 类。 当你创建 Enum 的子类时,它包含一组变量,每个变量都有自己的值,你可以在程序中使用这些变量。 例如,在前一种情况下,你将编写如下内容:
from enum import Enumclass WeekDay(Enum):
Monday = 1
Tuesday = 2
Wednesday = 3
Thursday = 4
Friday = 5
Saturday = 6
Sunday = 7
?
现在将变量设置为值
Friday
你可以写day = WeekDay.Friday
?
并且你还可以获取
Friday
表示的整数值:intDay = day.value # This will be 5
?
迭代器 迭代器是允许你迭代数据结构中的所有元素的类。 迭代器的一个例子是
range
函数:你可以迭代某个范围内的所有整数值(例如,通过使用 for 循环)。?
如果你想创建你自己的迭代器,你只需要实现
__next__
和 __iter__
方法。__iter__
应该返回迭代器对象(所以它在大多数情况下返回 self)__next__
应该返回数据结构的下一个元素
假设我们正在创建一个迭代器来向后循环遍历一个列表。 正确的做法是:
class Backward():
def __init__(self, data):
self.data = https://www.it610.com/article/data # The list we want to iterate
self.index = len(self.data)def __iter__(self):
return selfdef __next__(self):
if(self.index == 0):
raise StopIteration
else:
self.index -= 1
return self.data[self.index]
?
如你所见,如果没有更多元素要迭代,
__next__
函数应该引发 StopIteration 错误。 否则,它将返回下一个要查看的元素。 现在我们可以在 for 循环中使用 Backward 对象:bw = Backward([1,2,3,4,5])
for elem in bw:
print(elem)
?
输出结果将是:
5
4
3
2
1
以列表的形式访问类 ?
当我们使用列表时,我们可以使用方括号访问特定的值。 能够为我们自己的类实现类似的东西会很好。 我们可以使用
__getitem__
和 __setitem__
来做到这一点。 当我们使用方括号时,列表会调用以下方法:?
x = l[idx]
等价x = l.__getitem__(idx)
l[idx] = x
等价l.__setitem__(idx, x)
所以如果我们在我们的类中实现这两个方法,我们就可以像使用列表一样使用方括号。
?
这是一个非常简单的例子(它是一个大小不能改变的列表,其索引从 1 开始):
class MyList():
def __init__(self, dimension):
self.l = [0 for i in range(dimension)]def __getitem__(self, idx):
return self.l[idx-1]def __setitem__(self, idx, data):
self.l[idx-1]=dataml = MyList(5)
ml[1] = 50 # Set the first element of ml to 50
ml[2] = 100 # Set the second element of ml to 100
x = ml[1] # x is now 50
总结
- 使用
@property
创建常量 - 使用
@classmethod
创建多个类构造函数 - 使用
Enum
类创建枚举 - 使用
__next__
方法创建迭代器 - 像处理列表一样访问类,使用
__setitem__
和__getitem__
文章图片
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长