Python学习——数据模型/特殊方法

数据科学与人工智能

共 2689字,需浏览 6分钟

 ·

2020-10-19 01:08

数据模型其实是对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语言,有任何问题或者想法,请留言或者加群讨论

浏览 41
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报