文章导读:
1. 了解Python数据模型是什么
2. Python常见特殊方法示例
数据模型其实是对Python框架的描述,它规范了这门语言自身构架模块的接口,这些模块包括但不限于序列、迭代器、函数、类和上下文管理器。简单来说,数据模型就是Python自身的数据类型,及其包含的特殊方法。这些特殊方法在Java中也被成为‘魔术方法’
如len(object)调用了__len__特殊方法,list[]调用了__getitem__方法。从根本来说,这些特殊方法能让你的对象实现和支持与迭代、集合、属性访问、运算符、函数和方法、对象创建与销毁、字符串以及管理上下文的语言框架。list[]、+、-、*、/、for i in x这些写法是为了更简介和更具有可读性,实际都是通过特殊方法实现的。
特殊方法一览
如何调用特殊方法
- 特殊方法的调用是隐式的,通常你的代码无需直接使用特殊方法。除非有大量的元编程存在,直接调用特殊方法的频率应该远远低于你去实现它们的次数。唯一的例外可能是__init__方法,你的代码里可能经常会用到它,目的是在你的子类的__init__方法中调用超类的构造器。
- 通过内置的函数(例如len、iter、str等)来使用特殊方法是最好的选择。这些内置函数不仅会调用特殊方法,通常还提供额外的好处,而且对于内置的类来说,它们的速度更快。
- 不要自己想当然地随意添加特殊方法,比如_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》学习