Python的程序结构[1] -> 方法/Method[3] -> 魔术方法 __getattr__ 与代理模式
__getattr__ 方法
__getattr__ 方法当对象调用内部属性(包括方法等)且未找到对应属性的时候会调用的特殊方法。利用这一特性,可是对函数实现一个代理模式。
__getattr__方法实现代理模式
当有一个类中已完成了许多函数的定义,而另外一个类要调用这些函数时,最直接的方法是使用代理,重载类的 __getattr__ 方法, 并在该方法内利用 getattr() 实现对被代理对象的属性获取,从而实现一个代理模式,简化代码。
首先定义一个代理的对象类 Foo,实现几个方法,
1 class Foo:
2 def speak(self):
3 print('Speak hello world')
4
5 def act(self, action):
6 print('Act', action)
7
8 def eat(self, food, fruit):
9 print('Eat', food, fruit)
10
11 def place(self):
12 print('Place things by Foo')
现在,假设我们有两个类,一个不使用代理模式(NoProxy 类),一个使用代理模式(Proxy 类),需要实现相同的功能,
对于不使用代理的类,在类中要完成 Foo 的方法调用则需要对这些方法分别定义新方法并调用,方式如下,
1 class NoProxy:
2 def __init__(self):
3 self._foo = Foo()
4
5 def speak(self):
6 self._foo.speak()
7
8 def act(self, action):
9 self._foo.act(action)
10
11 def eat(self, food, fruit):
12 self._foo.eat(food, fruit)
13
14 def watch(self):
15 self.act('watching')
在 NoProxy 类中,speak / act / watch 三个方法分别调用 Foo 中的方法,同时还有一个自己的 watch 方法,但如果当需要代理的方法很多时,每一个方法都要进行二次定义,将十分麻烦,为此可以使用代理模式(使用基类继承也可以,略有区别)进行代码的简化。
1 class Proxy:
2 def __init__(self):
3 self._foo = Foo()
4
5 def __getattr__(self, item):
6 print('Use Proxy')
7 return getattr(self._foo, item)
8
9 def watch(self):
10 self.act('Watching')
11
12 def place(self):
13 print('Place things by Proxy')
从代码中可以看到,使用魔术方法 __getattr__ 可以实现一个简单的代理模式,当在 Proxy 类中搜索不到对应的属性或方法时(调用 __getattribute__ 方法),便会调用 __getattr__ 方法,此时则利用 getattr() 函数获取代理对象的对应方法再返回即可。
接着分别对两个类进行方法的调用,并在最后调用一个代理类中已存在的方法,证明代理只有在搜索不到方法的时候才会起作用。
1 for x in [NoProxy(), Proxy()]:
2 x.speak()
3 x.act('run')
4 x.eat('rice', 'apple')
5 x.watch()
6 Proxy().place()
最终,NoProxy 类输出的结果为,
Speak hello world
Act run
Eat rice apple
Act watching
而 Proxy 类输出的结果为,
Use Proxy
Speak hello world
Use Proxy
Act run
Use Proxy
Eat rice apple
Use Proxy
Act Watching
两者功能相同,但如果当代理对象的函数方法较多时,则使用代理模式能够使代码更加简洁。 最后,还可以看到当 Proxy 类和 Foo 类中的 place 方法都存在时,会优先使用 Proxy 类的方法。
Place things by Proxy
参考链接
http://www.jianshu.com/p/09f88a11928f
Python的程序结构[1] -> 方法/Method[3] -> 魔术方法 __getattr__ 与代理模式的更多相关文章
- Python的程序结构[1] -> 方法/Method[2] -> 魔术方法 __init__ / __del__ / __new__
魔术方法 / Magic Method 魔法方法就是可以给你的类增加魔力的特殊方法(实质应称为特殊方法,魔术方法在JavaScript中有所体现,对象具有不透明特性,而且无法在自定义对象中模拟这些行为 ...
- Python的程序结构[1] -> 方法/Method[4] -> 魔术方法 __call__ / __str__ / __repr__
__call__ 方法 __call__ 是当对象被调用时会调用的方法,允许一个对象(类的实例等)像函数一样被调用,也可以传入参数. 1 class Foo(): 2 def __init__(sel ...
- Python的程序结构[1] -> 方法/Method[0] -> 类实例方法、私有方法和抽象方法
类实例方法.私有方法和抽象方法 Python中最常用的就是类实例方法,类似于属性中的类实例属性,同时,也存在与私有属性类似方法,即私有方法,下面介绍这两种常见的方法,以及一种特殊意义的类实例方法 -- ...
- C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结。
C++/Php/Python/Shell 程序按行读取文件或者控制台方法总结. 一.总结 C++/Php/Python/Shell 程序按行读取文件或者控制台(php读取标准输入:$fp = fope ...
- Python的程序结构[1] -> 方法/Method[1] -> 静态方法、类方法和属性方法
静态方法.类方法和属性方法 在 Python 中有三种常用的方法装饰器,可以使普通的类实例方法变成带有特殊功能的方法,分别是静态方法.类方法和属性方法. 静态方法 / Static Method 在 ...
- Python的程序结构[4] -> 函数/Function[0] -> 函数与方法的区别
函数与方法的区别 / Distinction of Function and Method 关于函数与方法的区别,可根据两者的定义看出, 函数function -- A series of state ...
- Python的程序结构[7] -> 生成器/Generator -> 生成器浅析
生成器 / Generator 目录 关于生成器 生成器与迭代器 生成器的建立 通过迭代生成器获取值 生成器的 close 方法 生成器的 send 方法 生成器的 throw 方法 空生成器的检测方 ...
- Python的程序结构[2] -> 类/Class[1] -> 基类与继承
基类与继承 / Base Class and Inheritance Class 面向对象的特性使得 Python 中不可避免地需要使用到类和类的继承,类的继承可以使得代码很好的被重用.下面以一些代码 ...
- 零基础小白Python入门必看:面向对象之典型魔术方法
随机推荐
- 《Cracking the Coding Interview》——第18章:难题——题目3
2014-04-29 01:02 题目:从m个整数里随机选出n个整数,要求等概率. 解法:和洗牌的算法类似,每次随机抽出一个数,抽n次即可.时间复杂度O(m * n),空间复杂度O(m). 代码: / ...
- 《Cracking the Coding Interview》——第13章:C和C++——题目7
2014-04-25 20:18 题目:给定一个Node结构体,其中包含数据成员和两个Node*指针指向其他两个Node结构(还不如直接说这是个图呢).给你一个Node指针作为参数,请做一份深拷贝作为 ...
- eclipse集成python(Pydev插件安装)
1.下载PyDev的压缩包,解压后会有features和plugins两个文件夹,将两个文件夹的内容拷贝到eclipse对应的文件夹中,重新启动eclipse 2.配置python 2.1打开ecli ...
- Python导出sql语句结果到Excel
本文档是因为每周需要统计线上数据库中客户新增资源,手动执行实在是麻烦,就写了个脚本导出到Excel,顺便发一封邮件. (当然这不是线上的真实脚本,不过根据个人需求稍微修改下,还是可以直接用的.拿去不谢 ...
- Python网络编程(OSI模型、网络协议、TCP)
前言: 什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系. 在数学上,网络是一种图,一般认为专指加权图. 网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类 型的实际问题中抽象 ...
- Mac 电脑鼠标和触摸板滚动方向不一致的问题【已解决】
当我们使用鼠标连接到 MacBook 时,会发现无论怎么设置,鼠标和触摸板的滚动方向都是相反的,导致不能同时使用鼠标和触摸板 解决方法: 我安装了下面的程序,它只允许您反转鼠标的滚动行为: Scrol ...
- 聊聊、Java SPI
SPI,Service Provider Interface,服务提供者接口. Animal 接口 package com.rockcode.www.spi; public interface Ani ...
- [codeforces] 585D Lizard Era: Beginning || 双向dfs
原题 有n(n<=2)个任务和三个人,每次任务给出每个人能得到的值,每次任务选两个人,使n个任务结束后三个人得到的值是一样的.输出每次要派哪两个人,如果不行输出Impossible. n< ...
- Snakes and Ladders LightOJ - 1151( 概率dp+高斯消元)
Snakes and Ladders LightOJ - 1151 题意: 有100个格子,从1开始走,每次抛骰子走1~6,若抛出的点数导致走出了100以外,则重新抛一次.有n个格子会单向传送到其他格 ...
- vue的main.js
import Vue from 'vue'; import App from './App.vue'; //================http 请求======================= ...