反射
反射是在只知道类名或者函数名的情况下调用其对应的函数
对于本文件内的全局变量,可以使用globals()
函数获取全局变量 名称-值 的键值对
# return a dict name -> value
glodict = globals()
def foo():
dosomething()
pass
# run `foo()`
globals()['foo']()
对于类内变量, 使用__dict__
class Foo(object):
def __init__(self, **kwargs):
self.value1 = 1
self.value2 = 2
for name in kwargs:
if name in self.__dict__:
self.__dict__[name] = kwargs[name]
def dosomething(self):
dosomething_()
t = Foo(value1 = 100)
# t.value1 == 100 & t.value2 == 2
路由 eg:
class Dog(object):
def __int__(self, name):
self.name = name
def eat(self, food):
print('I love eat '+food)
def rout(url):
urls = url.split("&")
map = {}
for uri in urls:
u = uri.split('=')
map[u[0]] = u[1]
obj = globals()[map.get('cls')]()
func = getattr(obj, map.get('method'))
func(map.get('value'))#I love eat meat
rout("cls=Dog&method=eat&value=meat")
动态继承
eg:
对于图片来说,可能有PNG, JPG等格式
如果我们有一个ImageZip类, 无法确定继承自那种Image格式(PNGImage or JPGImage ? )
使用工厂函数自动创建类:
def image_factory(path):
# ...
if format == ".gz":
image = unpack_gz(path)
format = os.path.splitext(image)[1][1:]
if format == "jpg":
return MakeImageZip(ImageJPG, image)
elif format == "png":
return MakeImageZip(ImagePNG, image)
else: raise Exception('The format "' + format + '" is not supported.')
def MakeImageZIP(base, path):
'''`base` either ImageJPG or ImagePNG.'''
class ImageZIP(base):
# ...
return ImageZIP(path)
def ImageZIP(path):
path = unpack_gz(path)
format = os.path.splitext(image)[1][1:]
if format == "jpg": base = ImageJPG
elif format == "png": base = ImagePNG
else: raise_unsupported_format_error()
class ImageZIP(base): # would it be better to use ImageZip_.__name__ = "ImageZIP" ?
# ...
return ImageZIP(path)
hack 输出流
当项目有很多文件时,要找出控制台的输出是在哪里print出来的很麻烦
import sys,traceback
class mystdout:
stdout = sys.stdout
def write(self,_str):
if _str != '\n':
filepath,lineno = traceback.extract_stack()[-2][0:2]
mystdout.stdout.write("%s\t%s(%s)\n"%(_str,filepath,lineno))
sys.stdout = mystdout()
print 'foo'
print 'bar'
# 输出
# foo test_stdout.py(11)
# bar test_stdout.py(12)
当print 'foo'
的时候,会调用sys.stdout.write()
,不过因为sys.stdout = mystdout()
,被重写了,所以实际调用的是mystdout
类的write()
方法。 在python中print
会自动加换行符’\n’,而且是单独sys.stdout.write('\n')
,所以要if _str != '\n'
。 再加上traceback
获得文件名和行号,这样控制台的每个输出都能快速定位到在哪里print的了。
abc(Abstract Base Classes)
声明抽象函数
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def screaming(self):
'Return when animal screaming the sound hear likes'
return NotImplemented
@abc.abstractmethod
def walk(self, x, y):
'Make animal walk to position (x, y).'
return NotImplemented
>>> class Dog(Animal):
... pass
...
>>> Dog() # Create a instance
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Dog with abstract methods screaming, walk
支持classmethod,property
import abc
class Base(abc.ABC):
@classmethod
@abc.abstractmethod
def setUpClass(cls):
return NotImplemented
@staticmethod
@abc.abstractmethod
def count(self, data):
return len(data)
class Implementation(Base):
@classmethod
def setUpClass(cls):
cls.count = 0
@staticmethod
def count(self, data):
self.count = len(data)
return self.count
import abc
class Base(abc.ABC):
_index = 0
@property
@abc.abstractmethod
def index(self):
return self._index
@index.setter
@abc.abstractmethod
def index(self, new_index):
self._index = new_index
class Implementation(Base):
MAX_LEN = 100
@property
def index(self):
return self._index
@index.setter
def index(self, new_index):
new_index = min(new_index, self.MAX_LEN)
self._index = new_index
imp = Implementation()
print(imp.index)
imp.index = 50
print(imp.index)
imp.index = 500
print(imp.index)
weakref 弱引用
可以处理循环引用问题
import sys # We can use sys.getrefcount(obj) to get refcnt
class Foo(object):
pass
# Create Foo Object A
# And print reference count
A = Foo()
print('Refcnt of A: ', sys.getrefcount(A))
# Create a strong reference to A
# And check if B is reference to A
# Then print A refcnt, it should +1
B = A
print("A is B's referent: ", id(B) == id(A))
print('Refcnt of A: ', sys.getrefcount(A))
# Create three strong reference to A
# Refcnt of A should +3
C = A
D = A
E = A
print('Refcnt of A: ', sys.getrefcount(A))
# Delete E should -1 at A's refcnt
del E
print('Refcnt of A: ', sys.getrefcount(A))
import sys
import weakref
class Foo(object):
def show(self):
print('hello')
A = Foo()
print('Refcnt of A: ', sys.getrefcount(A))
B = weakref.ref(A)
print(B)
B().show()
print('Refcnt of A: ', sys.getrefcount(A))