Опишу задачу изначально на простом примере.
Например у нас есть модель User
class User(db.Model):
login = db.StringProperty()
email = db.StringProperty()
def get_avatar_path(self, size=48):
'''Путь к картинке с аватаром пользователя'''
return url_for('static', filename='avatars/' + self.login)
Нам нужно например изменить поведение класса, чтобы метод get_avatar_path возвращал не url аватара из статической папки, а, например, урл на сервис
gravatar.com.
Наследовать не получится - потому что все остальные части системы не будут об этом знать, т.к. знают только об User. После того, как создался объект наследника менять поведение не надо. Классы наследников - думаю да.
При обычном наследовании это было бы просто.
class GravatarUser(User):
def get_avatar_path(self, size=48):
default = super(GravatarUser, self).get_avatar_path(size)
hash = hashlib.md5(self.email.lower()).hexdigest()
gravatar_url = 'http://www.gravatar.com/avatar/' + hash + '?'
gravatar_url += urllib.urlencode({'d':default, 's':str(size)})
return gravatar_url
Таких базовых классов много, и методов которые можно переопределять - тоже.
Пришел в голову еще один страшный код:
import hashlib, urllib
_HANDLERS = {}
def has_realisation(rel_name):
def wrapper(func):
def inner(*argv, **kw):
def prev(i):
def g():
if i == len(handlers)-1:
return func(*argv, **kw)
return handlers[i+1](prev(i+1), *argv, **kw)
return g
handlers = _HANDLERS[rel_name]
if handlers:
return handlers[0](prev(0), *argv, **kw)
return func(*argv, **kw)
_HANDLERS[rel_name] = []
return inner
return wrapper
def is_realisation(rel_name):
def inner(func):
_HANDLERS[rel_name].insert(0, func)
return func
return inner
class User(object):
def __init__(self, login, email):
self.login = login
self.email = email
@has_realisation('avatar_path')
def get_avatar_path(self, size=48):
return '/static/avatars/%s/%d' % (self.login, size,)
user = User('test', 'test@example.com')
print user.get_avatar_path(96)
@is_realisation('avatar_path')
def gravatar(avatar, cls, size):
hash = hashlib.md5(cls.email.lower()).hexdigest()
gravatar_url = 'http://www.gravatar.com/avatar/' + hash + '?'
gravatar_url += urllib.urlencode({'d':avatar(), 's':str(size)})
return gravatar_url
print user.get_avatar_path(128)