当前位置: 首页 > 后端技术 > Python

【译文】5UnknownTricksforPythonClasses

时间:2023-03-26 14:07:52 Python

译文5UnknownTricksforPythonClassesPython有许多强大的特性,在处理类时提供了极大的灵活性。在这里,我将向您展示五个可以帮助您编写更好代码的高级功能。创建一个常量值假设我们正在创建一个Circle类。我们可能需要一种计算面积和计算周长的方法:classCircle():def__init__(self,radius):self.radius=radiusdefarea(self):return3.14*self.radius*self.radiusdefperimeter(self):return2*3.14*self.radius这个实现似乎可行,但是如果我们想把pi的值改得更精确怎么办?我们需要在两个地方改变它。一个更好的想法是将pi的值存储在一个变量中:classCircle():def__init__(self,radius):self.radius=radiusself.pi=3.14defarea(self):returnself.pi*self.radius*self.radiusdefperimeter(self):return2*self.pi*self.radius但是,现在任何人都可以更改pi的值。这不是一件好事:如果用户写这样的东西怎么办:c=Circle(4)c.pi=5这会破坏我们所有的功能!显然,我们必须为此做点什么。不幸的是,Python不允许创建常量。我们可以使用一个标有@property并返回pi的函数。这样,函数可以像没有括号的变量一样被调用。类Circle():def__init__(self,radius):self.radius=radius@propertydefpi(self):return3.14defarea(self):returnself.pi*self.半径*自身。radiusdefperimeter(self):return2*self.pi*self.radius现在pi的值不能被用户改变,它只存储在一个地方。多个类构造函数在Python中,类构造函数是使用__init__方法定义的。不幸的是,函数重载是不允许的,所以我们只能定义一个这样的函数。但是,有一种方法可以使用类构造函数之类的东西来做到这一点。这可以使用@classmethod标记来完成。例如,假设我们正在创建一个Date类。第一个构造函数是:classDate():def__init__(self,day,month,year):self.day=dayself.month=monthself.year=year现在我们可能想添加另一个构造函数,从dd/mm/yyyy格式的字符串。我们可以在Date类中创建一个类方法:@classmethoddeffromString(obj,s):day=int(s[:2])month=int(s[3:5])year=int(s[6:])returnobj(day,month,year)#返回一个新对象现在我们可以通过调用fromString方法创建一个新的Date对象:d=Date.fromString("21/07/2020")print(d.day,d.month,d.year)Output:2172020创建枚举假设您的程序中有一个代表星期几的变量。您可以将其表示为一个整数,例如1表示星期一,2表示星期二等。但是,这不是最佳选择,因为您必须记住是从0还是1开始。此外,当您打印值时,它会只是一个整数,所以你需要一个函数将它转换为正确的名称。幸运的是,我们可以使用枚举库中的枚举类。当您继承Enum时,它包含一组变量,每个变量都有自己的值,您可以在程序中使用这些变量。例如,在前一种情况下,您可以这样写:fromenumimportEnumclassWeekDay(Enum):Monday=1Tuesday=2Wednesday=3Thursday=4Friday=5Saturday=6Sunday=7现在将变量设置为对于Friday的值,你可以写day=WeekDay.Friday你也可以得到Friday表示的整数值:intDay=day.value#Thiswillbe5Iterators迭代器是允许你迭代所有元素的类数据结构。迭代器的一个示例是范围函数:您可以迭代特定范围内的所有整数值(例如,通过使用for循环)。如果你想创建自己的迭代器,你只需要实现__next__和__iter__方法。__iter__应该返回迭代器对象(因此在大多数情况下它返回self)__next__应该返回数据结构的下一个元素假设我们正在创建一个迭代器来向后循环遍历列表。正确的做法是:classBackward():def__init__(self,data):self.data=data#Thelistwewanttoiterateself.index=len(self.data)def__iter__(self):returnselfdef__next__(self):if(self.index==0):raiseStopIterationelse:self.index-=1returnself.data[self.index]如您所见,如果没有更多元素要迭代,则__next__函数应该引发StopIteration错误。否则,它返回下一个要查看的元素。现在我们可以在for循环中使用Backward对象:bw=Backward([1,2,3,4,5])foreleminbw:print(elem)Theoutputwillbe:54321accessingtheclassasalist当我们使用列表时,我们可以使用方括号访问特定的值。能够为我们自己的类实现类似的东西会很好。我们可以使用__getitem__和__setitem__来做到这一点。当我们使用方括号时,list调用了如下方法:x=l[idx]等价于x=l.__getitem__(idx)l[idx]=x等价于l.__setitem__(idx,x)所以如果我们在我们的类中实现这两个方法允许我们像使用列表一样使用方括号。这里有一个非常简单的例子(它是一个大小不能改变的列表,它的索引从1开始):classMyList():def__init__(self,dimension):self.l=[0foriinrange(dimension)]def__getitem__(self,idx):returnself.l[idx-1]def__setitem__(self,idx,data):self.l[idx-1]=dataml=MyList(5)ml[1]=50#Setml的第一个元素为50ml[2]=100#Setml的第二个元素为100x=ml[1]#x现在是50总结使用@property创建常量使用@classmethod创建多个类构造函数使用EnumClass创建枚举使用__next__方法创建迭代器访问类如列表,使用__setitem__和__getitem__