Метакласовете в Python са много яко нещо. Макар все още да не ми се е наложило да напиша дори един такъв за работата си, са много полезен източник на забавления. Сега ще ви покажа как с малко остроумие може да дефинирате класове по следния интересен начин:
class Person(object):
__metaclass__ = selfless
def __init__(name, age):
self.name = name
self.age = age
def __repr__():
return "Person(%s, %d)" % (repr(self.name), self.age)
def sayHi():
print "Hello, I’m %s and I’m %d years old" % (self.name, self.age)
def rename(newName):
self.name = newName
__metaclass__ = selfless
def __init__(name, age):
self.name = name
self.age = age
def __repr__():
return "Person(%s, %d)" % (repr(self.name), self.age)
def sayHi():
print "Hello, I’m %s and I’m %d years old" % (self.name, self.age)
def rename(newName):
self.name = newName
Интересното? Въобще не ви се налага да пишете self
пред имената на методите.
Как го постигам? Доста просто:
from types import FunctionType
class selfless(type):
def __new__(cls, name, bases, classDict):
for attr in classDict:
if not isinstance(classDict[attr], FunctionType): continue
classDict[attr] = selflessWrapper(classDict[attr])
return type.__new__(cls, name, bases, classDict)
def selflessWrapper(func):
def wrapper(self, *args, **kwargs):
hadSelf, oldSelf = func.func_globals.has_key(‘self’), \
func.func_globals.get(‘self’)
func.func_globals[‘self’] = self
returnValue = func(*args, **kwargs)
if hadSelf:
func.func_globals[‘self’] = oldSelf
else:
del func.func_globals[‘self’]
return returnValue
wrapper.func_name = func.func_name + "_wrapper"
return wrapper
class selfless(type):
def __new__(cls, name, bases, classDict):
for attr in classDict:
if not isinstance(classDict[attr], FunctionType): continue
classDict[attr] = selflessWrapper(classDict[attr])
return type.__new__(cls, name, bases, classDict)
def selflessWrapper(func):
def wrapper(self, *args, **kwargs):
hadSelf, oldSelf = func.func_globals.has_key(‘self’), \
func.func_globals.get(‘self’)
func.func_globals[‘self’] = self
returnValue = func(*args, **kwargs)
if hadSelf:
func.func_globals[‘self’] = oldSelf
else:
del func.func_globals[‘self’]
return returnValue
wrapper.func_name = func.func_name + "_wrapper"
return wrapper
В общи линии, създавам нов метаклас, който барва всички функции на инстанциите си. Разширява ги с по един аргумент, а в глобалната им област на видимост добавя едно ново име (self
), което след това възстановява. В резултат, всяка функция вижда self
, а самия клас вижда функциите като такива с един аргумент повече. Едва ли е нужно да казвам, че цялата врътка става във selflessWrapper
.