python加载模型_Python数据模型的引入和使用。

数据模型其实是对Python框架的概述,它规范了这门语言自身构建模块的接口,这些模块包括但不限于序列、迭代器、函数、类和上下文管理器。

不管在哪一种框架下写代码,都会花费大量时间去实现那些会被框架本身调用的方法,Python也不例外。Python解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作。

特殊方法一般用两个下划线开头,用两个下划线结尾。例如 __getitem__方法,obj[key]背后就是这个方法。比如为了求得 my_collection的值,解释器实际上调用的是my_collection[key].__getitem__(key)。

下面引出一个例子,来说明 __getitem__和 __len__这两个特殊方法。

下面是一个纸牌类:

# 一摞有序的纸牌

import collections

from random import choice

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 suit in self.suits for rank in self.ranks]

def __len__(self):

return len(self._cards)

def __getitem__(self, position):

return self._cards[position]

然后输入:

# 测试输出

beer_card = Card('7', 'diamonds')

print(beer_card)

会得到:

Card(rank='7', suit='diamonds')

也可以用:

deck = FrenchDeck()

print(len(deck))

用上述代码可以查看一叠牌有多少张。

随机抽取纸牌也可以用内置的方法,Python的内置函数 random.choice可以直接用在这一摞纸牌实例上。

于是你就会发现,实现特殊方法利用Python的数据模型的好处:作为你的类的用户,他们不必去记住标准操作的各式名称(例如得到函数总数是.size()还是.length()还是别的什么函数。)。

可以直接用Python标准库,比如random.choice函数,而不用重新造轮子。

其他的函数你也可以使用,比如reversed和sorted这些函数。对合成的应用可以让__len__和__getitem__方法的具体实现可以代理给self._cards这个Python列表(list对象)。

下面说一下如何使用特殊方法:

特殊方法的存在是为了被解释器调用的,自己并不需要调用他们。并不存在,my_object.__len__()这种写法。应该使用len(my_object)。如果my_object是一个自定义类的对象,那么Python回去调用由你实现的__len__方法。

很多时候特殊方法的调用都是隐式的,比如for i in x:这一个语句背后用的是iter(x)。函数背后则是x.__iter__()方法。前提是这个方法被实现了。

一般来说,直接调用特殊方法的次数会比较少,除非有大量的元编程存在。或者是__init__方法。

用内置函数会有额外的效果,内置的类速度也会更快。

然后我们在这里引入一个例子:

利用“+”实现向量加法的运算。

然后利用__repr__、__abs__、__add__和__mul__特殊方法可以实现。

下面是示例代码:

# 实现一个简单的二维向量类

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 __abs__(self):

# return hypot(self.x, self.y)

#

# def __bool__(self):

# return bool(abs(self))

# 更高效的bool方法

def __bool__(self):

return bool(self.x or self.y)

def __add__(self, other):

x = self.x + other.x

y = self.y + other.y

return Vector(x, y)

def __mul__(self, scalar):

return Vector(self.x * scalar, self.y * scalar)

然后输入测试用例:

v1 = Vector(2, 4)

v2 = Vector(2, 1)

v = v1 + v2

print(v)

然后会返回结果:

Vector(4, 5)

这里面虽然有6个特殊的方法,但是除了__init__方法,其他方法并不会在这个类自身的代码中使用。一般只有Python的解释器会频繁的直接调用这些方法。

下面说其中的特殊方法的实现,第一个是字符串表示形式:

Python有个内置函数是repr,它能把一个对象用字符串的形式表达出来以便辨认,这就是“字符串表示形式”。repr 就是通过 __repr__ 这个特殊方法来得到一个对象的字如果没有实现 __repr__,当我们在控制台里打印一个向量的实例时,得到的字符串可能会是 。

在 __repr__ 的实现中,用到了 %r 来获取对象各个属性的标准字符串表示形式——

这是个好习惯,它暗示了一个关键:Vector(1, 2) 和 Vector('1', '2') 是不一样的,后者在我们的定义中会报错,因为向量对象的构造函数只接受数值,不接受字符串。

然后说一下__repr__和__str__的区别,后者是在str()函数被人使用,或者是在用print函数打印一个对象的时候才会被调用,返回的字符串会更友好一点。

如果想实现这两个特殊方法其中的一个的话,__repr会是更好的选择,因为一个对象如果没有__str__函数,儿Python又需要调用它的时候,解释器会用__repr__代替。

然后说第二个实现,算术运算符:

上面的例子,通过__add__和__mul__,带来了“+”“*”两个算术运算符。值得注

意的是,这两个方法的返回值都是新创建的向量对象,被操作的两个向量(self 或

other)还是原封不动,代码里只是读取了它们的值而已。中缀运算符的基本原则就是不

改变操作对象,而是产出一个新的值。

然后说最后一个实现,自定义的bool值:

尽管 Python 里有 bool 类型,但实际上任何对象都可以用于需要布尔值的上下文中(比如

if 或 while 语句,或者 and、or 和 not 运算符)。为了判定一个值 x 为真还是为假,

Python 会调用 bool(x),这个函数只能返回 True 或者 False。

默认情况下,我们自己定义的类的实例总被认为是真的,除非这个类对 __bool__ 或者

__len__ 函数有自己的实现。bool(x) 的背后是调用 x.__bool__() 的结果;如果不存

在 __bool__ 方法,那么 bool(x) 会尝试调用 x.__len__()。若返回 0,则 bool 会返回

False;否则返回 True。

我们对 __bool__ 的实现很简单,如果一个向量的模是 0,那么就返回 False,其他情况

则返回 True。因为 __bool__ 函数的返回类型应该是布尔型,所以我们通过

bool(abs(self)) 把模值变成了布尔值。

下面列出,特殊方法的(表来自流畅的Python和Python的官方文档):

然后是跟运算符相关的特殊方法:

说到这里,文章就快结束了。通过实现特殊方法,自定义数据类型可以表现的跟内置类型一样,从而让我们写出更具有表达力的代码。或者说更具有Python风格的代码。

Python中对象的一个基本要求就是它得有合理的字符串的表示形式,而__repr__和__str__就很满足这个要求,前者用来调试,后者用来给终端用户看。

Python通过运算符重载这个模式提供了很多的数值类型,有兴趣的话,可以查一下相关的资料。

另外,Python数据模型另外的一个写法就是Python对象模型,而特殊方法在某些语言中经常也被叫做魔术方法。

另外一个名词就是元对象,元对象是指那些对构建语言本身来讲很重要的对象,以此为前提,元对象协议中的协议可以看做接口,也就是说,元对象协议是对象模型的同义词,他们的意思都是构建核心语言的API。

讲到这里,文章就结束了。谢谢大家关注。

笔者,最近得了重感冒。一直咳嗽,过了一周了,还没有变好的趋势。

大家一定注意身体,多喝热水真的不是说说。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值