定义
首先定义下什么是“占位对象”,以下面这一小段代码为例,
from foo import Foo
def foobar():
f = Foo()
f.execute()
比如上述Foo代表了游戏客户端引擎代码,我们希望在服务端运行同一份代码,但服务端没有客户端引擎环境,直接运行代码必然会出现异常。服务端运行代码时并不关心表现层逻辑,只要让引擎相关代码都不发生效用又不抛出异常就可以。因此我们需要一个占位对象,让其替换那些不想关心的类。这样就能够在客户端服务端共享部分代码,而无需重复实现。
Placeholder实现
在明确了目标之后,下面就一步步来实现具体的功能点,从最简单的类原型开始,Placeholder即需要最终实现的占位类。
class Placeholder(object):
pass
对象构造处理
首先要解决的就是构造问题,让__init__
支持变长参数,就能够支持如下任意构造调用方式,
class Placeholder(object):
def __init__(self, *args, **kwargs):
super(Placeholder, self).__init__()
Placeholder()
Placeholder('foobar')
函数调用处理
接着来看函数调用处理,为了让调用未定义函数不抛异常,就需要重载__getattribute__
。同时为了支持级联调用,需要重载__call__
,让Placeholder成为callable对象,
class Placeholder(object):
...
def __call__(self, *args, **kwargs):
return self
def __getattribute__(self, name):
try:
return object.__getattribute__(self, name)
except:
return self
placeholder = Placeholder()
placeholder.foo().bar()
支持迭代访问、下标访问
让Placeholder支持迭代访问,以及in操作,需要处理__iter
,
class Placeholder(object):
...
def __iter__(self):
return self
def next(self):
raise StopIteration
p = Placeholder()
for i in p:
print i
逻辑判断处理
Placeholder参与比较判断时,让其永远返回False,
class Placeholder(object):
...
def __nonzero__(self):
return False
def __eq__(self, other):
return False
def __ne__(self, other):
return False
def __lt__(self, other):
return False
def __le__(self, other):
return False
def __gt__(self, other):
return False
def __ge__(self, other):
return False
p1 = Placeholder()
p2 = Placeholder()
print p1 == p2, p1 != p2, p1 < p2, p1 > p2 # False False False False
数学计算处理
Placeholder尽量避免参与数学计算,毕竟它是为了替换类而非数字。如果要处理也可以针对数学运算、位运算进行一定处理,但计算结果的含义需要注意,
class Placeholder(object):
...
def __neg__(self):
return self
def __add__(self, other):
return self
def __iadd__(self, other):
return self
def __sub__(self, other):
return self
def __isub__(self, other):
return self
def __mul__(self, other):
return self
def __imul__(self, other):
return self
def __div__(self, other):
return self
def __idiv__(self, other):
return self
def __mod__(self, other):
return self
def __imod__(self, other):
return self
def __divmod__(self, other):
return self
def __and__(self, other):
return self
def __iand__(self, other):
return self
def __or__(self, other):
return self
def __ior__(self, other):
return self
def __xor__(self, other):
return self
def __ixor__(self, other):
return self
def __invert__(self):
return self
def __lshift__(self, other):
return self
def __ilshift__(self, other):
return self
def __rshift__(self, other):
return self
def __irshift__(self, other):
return self
将简单数学计算、位运算相关函数全部重载之后,计算问题也可以解决,
p = Placeholder()
print p + 1, p * 1, p / 1, p % 1, p & 1
import处理
import需要分几种情况进行处理,
无子模块的package
对于没有子模块的package,外界import的方式有,
from foo import Foo
import foo
为了替换foo的实现,需要生成对应的一份py文件,在import之后将sys.modules中记录的module替换成Placeholder实例。
# foo/__init__.py
from placeholder import Placeholder
import sys
sys.modules[__name__] = Placeholder()
在import时获取到的就是Placeholder对象,
from foo import Foo
import Foo
含有子模块的package
在from import中会出现级联访问,
from foo.bar import Bar
from foo import Foo
因此不能再像上一种处理方式那样修改sys.modules,否则会出现异常,在生成的替代文件中,需要为每一层子模块创建对应的替代文件,对非模块变量,则在生成py中直接设置其为Placeholder,
# foo/__init__.py
from placeholder import Placeholder
import sys
Foo = Placeholder()
# foo/bar/__init__.py
from placeholder import Placeholder
import sys
sys.modules[__name__] = Placeholder()
替代代码生成需要脚本化。不过这种方式并不完备,处理不了动态加载的代码。
总结
语言的动态特性可以帮助实现一些看着很“奇怪”的需求,借着这个机会又熟悉了下Python的部分特性。