首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

python 魔术方法:让自定义类更像内置类型

关键时刻,第一时间送达!

Python的魔术方法是Python中那些预定义的像__XXX__类型的函数。

使用Python的魔术方法的最大优势在于python提供了简单的方法让对象可以表现得像内置类型一样。

__str__函数

__str__函数用于处理打印实例本身的时候的输出内容。如果没有覆写该函数,则默认输出一个对象名称和内存地址。

例如:

>>>classStudent(object):

...def __init__(self,name):

...self._name=name

...

>>>print Student()

输出:

.

那么我们如何让输出的结果可读性更高一点呢?我们可以覆写__str__函数。例如

>>>classStudent(object):

...def __init__(self,name):

...self._name=name

...def __str__(self):

...return"I'm a student, named %s"%self._name

...

>>>print Student("Charlie")

输出结果就是:I'm a student, named Charlie.

我们将str()函数作用于该对象的时候,其实是调用了该对象的__str__函数。

__repr__ 函数

__repr__也是将对象序列化,但是__repr__更多的是给python编译器看的。__str__更多的是可读性(readable)。

我们将repr()函数作用于摸某一个对象的时候,调用的其实就是该函数的__repr__函数。

与repr()成对的是eval()函数。eval()函数是将序列化后的对象重新转为对象。前提是该对象实现了__repr__函数。

上面这一段话基于自己的理解,不知道对错。

>>>item=[1,2,3]

>>>repr(item)

'[1, 2, 3]'

>>>other_item=eval(repr(item))

>>>other_item[1]

2

__iter__函数

我们经常对list或者tuple使用for…in…来迭代。那是list继承自Iterable。Iterable实现了__iter__函数。

要想将一个自定义的对象变成一个可迭代的对象,那么必须要实现两个方法:__iter__和next.

__iter__函数返回一个对象。迭代的时候则会不断地调用next函数拿到下一个值,直到捕获到StopIteration停止。

廖雪峰老师教程里写的是__next__方法,不知道为啥。

classFib(object):

def __init__(self):

self.a,self.b=,1

def __iter__(self):

returnself

def next(self):

self.a,self.b=self.b,self.a+self.b

ifself.a>10000:

raise StopIteration

returnself.a

foriinFib():

printi

__getitem__函数

上面通过实现__iter__函数实现对象的迭代。

那么如何实现对象按下标取出元素呢。

这是通过实现对象的__getitem__方法。

我们来举一个子。我们新建了一个类MyList,我们要办它实现普通list的一些功能,比如(1)根据下标获取值;(2)正数顺序单步长切片 (3)任意步长切片

classMyList(object):

def __init__(self,*args):

self.numbers=args

def __getitem__(self,item):

returnself.numbers[item]

my_list=MyList(1,2,3,4,6,5,3)

printmy_list[2]

当然,上面实现了根据下标获取值。但是这还不够。我们还需要实现切片功能。例如my_list[1:3].

我们对对象进行切片操作的时候,调用的气势也是__getitem__函数。此时,该函数获取到的并不是int对象,而是slice对象。

例如下面的代码

classMyList(object):

def __init__(self,*args):

self.numbers=args

def __getitem__(self,item):

ifisinstance(item,int):

returnself.numbers[item]

elif isinstance(item,slice):

# 写习惯了其他语言,差点忘记了三元运算符的格式了,吼吼吼。

# 下面句三元运算符的意思是,若为空,则为切片从0开始。

# 下面句三元运算符的意思是,若为空,则为切片到最末端结束。

returnself.numbers[start:stop]

my_list=MyList(1,2,3,4,6,5,3)

printmy_list[2:5]

上面的代码终于实现了切片功能,但是还没考虑负数呢。那么我们加一把劲再来改一下。代码如下:

classMyList(object):

def__init__(self,*args):

self.numbers=args

def__getitem__(self,item):

ifisinstance(item,int):

returnself.numbers[item]

elifisinstance(item,slice):

length=len(self.numbers)

start=length+start+1ifstart

stop=length+stop+1ifstop

returnself.numbers[start:stop]

my_list=MyList(1,2,3,4,6,5,3)

printmy_list[1:-1]

哇塞,写完了,棒棒棒

__getattar__

在调用某一个对象不存在的属性或者方法的时候,会抛出一个一个AttributeError错误。

但是如果我们实现了类中的魔术方法__getattar__,那么在调用不存在的属性或者方法的时候,就会调用该魔术方法。

classApple(object):

def __getattr__(self,item):

ifitem=="attar1":

return"print"

ifitem=="method1":

returnlambdax:"hello %s"%x

apple=Apple()

printapple.attar1

printapple.method1

__getattar__函数一个重要的适用场景就是实现链式调用。例如我们在调用某一个api的时候:

GET users/articles/index

思考一下,要实现链式调用,最重要的就是每一个调用都是返回一个实例~~。

# coding=utf-8

classApi(object):

def __init__(self,path=''):

self._path=path

def __getattr__(self,name):

returnApi("%s/%s"%(self._path,name))

# 定义一个Post方法来发送请求

def post(self):

printself._path

api=Api()

廖雪峰在他的教程中给我们出了一个题目:

例如调用github的api:users/:user/repos一样,中间的user名需要动态替换。

我们希望能api.users("charlie").repos这么调用。那么代码该如何实现呢?这可能需要用到另一个方法__call__

__call__ 函数

一个对象既有属性,又有方法。我们在调用一个实例的方法的时候,我们可以使用instance.method()的形式调用。

其实也可以将实例本身看成一个函数用来调用,我们需要做的就是实现__call__函数本身。

classApple(object):

def __call__(self,*args,**kwargs):

returnargs

apple=Apple()

print apple("yes","no")

此时我们再来看一下上面提到的实现api.users("charlie").repos链式调用的方法。

# coding=utf-8

classApi(object):

def __init__(self,path=''):

self._path=path

def __getattr__(self,name):

returnApi("%s/%s"%(self._path,name))

def __call__(self,args):

self._path="%s/%s"%(self._path,args)

returnApi(self._path)

# 定义一个Post方法来发送请求

def post(self):

printself._path

api=Api()

api.users("Charlie").index.post()

来源:charliecharlie

segmentfault.com/a/1190000008013646

程序员大咖整理发布,转载请联系作者获得授权

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180216B097VX00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券