Python学习——数据模型/特殊方法
数据模型其实是对Python框架的描述,它规范了这门语言自身构架模块的接口,这些模块包括但不限于序列、迭代器、函数、类和上下文管理器。简单来说,数据模型就是Python自身的数据类型,及其包含的特殊方法。这些特殊方法在Java中也被成为‘魔术方法’。
如len(object)调用了__len__特殊方法,list[]调用了__getitem__方法。从根本来说,这些特殊方法能让你的对象实现和支持与迭代、集合、属性访问、运算符、函数和方法、对象创建与销毁、字符串以及管理上下文的语言框架。list[]、+、-、*、/、for i in x这些写法是为了更简介和更具有可读性,实际都是通过特殊方法实现的。
如何调用特殊方法
1.特殊方法的调用是隐式的,通常你的代码无需直接使用特殊方法。除非有大量的元编程存在,直接调用特殊方法的频率应该远远低于你去实现它们的次数。唯一的例外可能是__init__方法,你的代码里可能经常会用到它,目的是在你的子类的__init__方法中调用超类的构造器。
2.通过内置的函数(例如len、iter、str等)来使用特殊方法是最好的选择。这些内置函数不仅会调用特殊方法,通常还提供额外的好处,而且对于内置的类来说,它们的速度更快。
3.不要自己想当然地随意添加特殊方法,比如_foo_之类的,因为虽然现在这个名字没有被python内部使用,以后就不一定了。
部分示例
__len__
class Test:
def __len__(self): #重写__len__方法
return 1
if __name__=="__main__":
t = Test()
print(len(t)) #输出为1
__getitem__
import collections
Card = collections.namedtuple('Card',['rank','suit'])
class FrenchDeck:
ranks = [str(n) for n in range(2,11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank,suit) for rank in self.ranks
for suit in self.suits]
def __getitem__(self, item):
return self._cards[item]
if __name__=="__main__":
deck = FrenchDeck()
print(deck[0]) #使用deck[0]时会调用__getitem__方法,解释器会将0传递给__getitem__(self, item)中的item参数
print(deck[1:4]) #使用切片操作时也会调用__getitem__方法,解释器会传递slice(1, 4, None)item参数
__repr__、__str__、__abs__、__add__、__mul__、__bool__
from math import hypot
class Vector:
def __init__(self,x=0,y=0):
self.x = x
self.y = y
def __repr__(self):
return "Vector(%r,%r)" % (self.x,self.y)
def __str__(self): # 如果类中同时有__str__和__repr__,则调用print是会先使用__str__
return "Vector(%r,%r)" % (self.x,self.y)
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Vector(x, y)
def __abs__(self): # abs本来是绝对值,在二维向量中指模
return hypot(self.x, self.y) #返回三角形的斜边
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __bool__(self):
return bool(abs(self))
if __name__ == "__main__":
v = Vector(3,4)
print(v) #返回Vector(3,4)
if v:
print(abs(v)) #返回5.0
v2 = Vector(1,2)
print(v * 3) #返回Vector(9,12)
print(v + v2) #返回Vector(4,6)
__repr__和__str__的区别在于,后者是在str()函数中被使用,或是在用print打印函数打印一个对象的时候才被调用。如果你只想实现这两个特殊方法中的一个,__repr__是更好的选择,因为如果一个对象没有__str__函数,而python又需要调用它的时候,解释器会用__repr__作为代替。
因此在使用print()函数时,解释器会按照__str__,__repr__的顺序寻找。
公众号推荐:数据思践
数据思践公众号记录和分享数据人思考和践行的内容与故事。
《数据科学与人工智能》公众号推荐朋友们学习和使用Python语言,需要加入Python语言群的,请扫码加我个人微信,备注【姓名-Python群】,我诚邀你入群,大家学习和分享。
关于Python语言,有任何问题或者想法,请留言或者加群讨论。