廖雪峰Python教程1轮还没学明白的(3) -- 面向对象高级编程 -- 定制类 -- __getattr__之链式调用
2017-06-21 22:58
1061 查看
原文链接:
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319098638265527beb24f7840aa97de564ccc7f20f6000#0
正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。比如定义
调用
错误信息很清楚地告诉我们,没有找到
要避免这个错误,除了可以加上一个
当调用不存在的属性时,比如
返回函数也是完全可以的:
只是调用方式要变为:
注意,只有在没有找到属性的情况下,才调用
此外,注意到任意调用如
这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。
这种完全动态调用的特性有什么实际作用呢?作用就是,可以针对完全动态的情况作调用。
举个例子:
现在很多网站都搞REST API,比如新浪微博、豆瓣啥的,调用API的URL类似:
http://api.server/user/friends
http://api.server/user/timeline/list
如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且,API一旦改动,SDK也要改。
利用完全动态的
试试:
这样,无论API怎么变,SDK都可以根据URL实现完全动态的调用,而且,不随API的增加而改变!
还有些REST API会把参数放到URL中,比如GitHub的API:
调用时,需要把
就可以非常方便地调用API了。有兴趣的童鞋可以试试写出来。
暂时没看懂,先标记吧。
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319098638265527beb24f7840aa97de564ccc7f20f6000#0
__getattr__
正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。比如定义Student类:
class Student(object): def __init__(self): self.name = 'Michael'
调用
name属性,没问题,但是,调用不存在的
score属性,就有问题了:
>>> s = Student() >>> print(s.name) Michael >>> print(s.score) Traceback (most recent call last): ... AttributeError: 'Student' object has no attribute 'score'
错误信息很清楚地告诉我们,没有找到
score这个attribute。
要避免这个错误,除了可以加上一个
score属性外,Python还有另一个机制,那就是写一个
__getattr__()方法,动态返回一个属性。修改如下:
class Student(object): def __init__(self): self.name = 'Michael'
def __getattr__(self, attr):
if attr=='score':
return 99
当调用不存在的属性时,比如
score,Python解释器会试图调用
__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回
score的值:
>>> s = Student() >>> s.name 'Michael' >>> s.score 99
返回函数也是完全可以的:
class Student(object): def __getattr__(self, attr): if attr=='age': return lambda: 25
只是调用方式要变为:
>>> s.age() 25
注意,只有在没有找到属性的情况下,才调用
__getattr__,已有的属性,比如
name,不会在
__getattr__中查找。
此外,注意到任意调用如
s.abc都会返回
None,这是因为我们定义的
__getattr__默认返回就是
None。要让class只响应特定的几个属性,我们就要按照约定,抛出
AttributeError的错误:
class Student(object): def __getattr__(self, attr): if attr=='age': return lambda: 25raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)
这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段。
这种完全动态调用的特性有什么实际作用呢?作用就是,可以针对完全动态的情况作调用。
举个例子:
现在很多网站都搞REST API,比如新浪微博、豆瓣啥的,调用API的URL类似:
http://api.server/user/friends
http://api.server/user/timeline/list
如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且,API一旦改动,SDK也要改。
利用完全动态的
__getattr__,我们可以写出一个链式调用:
class Chain(object): def __init__(self, path=''): self._path = path def __getattr__(self, path): return Chain('%s/%s' % (self._path, path)) def __str__(self): return self._path __repr__ = __str__
试试:
>>> Chain().status.user.timeline.list '/status/user/timeline/list'
这样,无论API怎么变,SDK都可以根据URL实现完全动态的调用,而且,不随API的增加而改变!
还有些REST API会把参数放到URL中,比如GitHub的API:
GET /users/:user/repos
调用时,需要把
:user替换为实际用户名。如果我们能写出这样的链式调用:
Chain().users('michael').repos
就可以非常方便地调用API了。有兴趣的童鞋可以试试写出来。
暂时没看懂,先标记吧。
相关文章推荐
- 廖雪峰Python教程1轮还没学明白的(2) -- 面向对象高级编程 -- 定制类 -- 实现Fib数列的__getitem__()/切片方法
- 廖雪峰Python教程1轮还没学明白的(1) -- 面向对象高级编程 -- 定制类 -- 斐波那契数列
- 廖雪峰Python教程 学习笔记11 面向对象高级编程
- Python 面向对象高级编程――定制类
- python Class:面向对象高级编程 __getattr__
- 廖雪峰Python教程1轮还没学明白的(4) -- IO编程 -- 序列化 -- JSON进阶
- 【Python】学习笔记——-8.4、面向对象高级编程:4.定制类
- 【Python】[面向对象高级编程] 多成继承,定制类,使用枚举
- 【廖雪峰Python习题集】面向对象高级编程
- Python 面向对象高级编程――使用枚举和元类
- python 面向对象高级编程
- 【Python】学习笔记——-8.2、面向对象高级编程:2.使用@property
- Python学习----面向对象高级编程
- Python基础之六面向对象高级编程
- python 2.7 : 面向对象高级编程
- 【Python】学习笔记——-8.3、面向对象高级编程:3.多重继承
- Python3 基础:面向对象高级编程(上)
- Python 第五章 面向对象高级编程
- python第七天学习记录——面向对象高级以及socket编程
- python 面向对象高级编程