Форум сайта python.su
Всем спасибо.
Вариант с фабрикой также придется дополнить методом регистрации новой реализации.
Накидал небольшой прототип.
_IMPLEMENTATIONS = {}
class Factory(object):
def __init__(self, implementation_selector):
self._implementation_selector = implementation_selector
@classmethod
def register_implementation(cls, implementation):
_IMPLEMENTATIONS.setdefault(cls.__name__, {})[
implementation.name] = implementation()
def __call__(self):
return _IMPLEMENTATIONS[self.__class__.__name__][
self._implementation_selector()]
def __getattr__(self, name):
return getattr(self(), name)
class Implementation(object):
name = None
class AvatarFactory(Factory):
'''Avatar'''
class AvatarDefaultImplementation(Implementation):
name = 'default'
def get_avatar_path(self, user, size=48):
return '/static/avatars/%s/%d' % (user.login, size,)
class GrvatarImplementation(Implementation):
name = 'gravatar'
def get_avatar_path(self, user, size=48):
import hashlib, urllib
hash = hashlib.md5(user.email.lower()).hexdigest()
gravatar_url = 'http://www.gravatar.com/avatar/' + hash + '?'
gravatar_url += urllib.urlencode({'s':str(size)})
return gravatar_url
AvatarFactory.register_implementation(AvatarDefaultImplementation)
AvatarFactory.register_implementation(GrvatarImplementation)
implementation = 'default'
def implementation_selector():
return implementation
class User(object):
avatar = AvatarFactory(implementation_selector)
def __init__(self, login, email):
self.login = login
self.email = email
def get_avatar_path(self, size=48):
return self.avatar.get_avatar_path(self, size)
user = User('login', 'test@example.com')
user2 = User('test2', 'test2@example.com')
print user.get_avatar_path()
print user2.get_avatar_path()
implementation = 'gravatar'
print user.get_avatar_path()
print user2.get_avatar_path()
class User(object):
avatar = AvatarFactory(...)
amount = AmountFactory(...)
gender = GenderFactory(...)
some_future = SomeFutureFactory(...)
...
class AvatarFactory(Factory):
'''Avatar'''
class User(db.Model):
...
@factory(AvatarFactory):
def get_avatar_path(self, size=48):
return 'default path'
Отредактировано (Фев. 16, 2011 13:34:46)
Офлайн
А если класс User переименовать в BaseUser, и приравнять User = BaseUser, а потом когда надо переопределить?
А в своем толстом проекте я сделал глобальный метод, который раздавал мне экземпляры классов в зависимости от параметров:
user = getObject('User',params)
Офлайн
У меня какое-то смутное ощущение, что я наблюдаю торжество проектировщика над здравым смыслом. Может быть я и не прав.
Офлайн
Вот такой можно фокус сделать - при создании экземпляра класса User, создавать экземпляр нужно го класса:
# coding: utf8
_classes = {}
class Base(object):
def __new__(self):
try:
return _classes[self.__name__]()
except KeyError:
return super(Base,self).__new__(self)
##############
class User(Base):
login = 'anonim'
def getlogin(self):
return self.login
##############
class MyUser(User):
def getlogin(self):
return 'x ' + self.login
###############
user = User()
print user, user.getlogin()
_classes['User'] = MyUser
user = User()
print user, user.getlogin()
<__main__.User object at 0xb76f5a8c> anonim
<__main__.MyUser object at 0xb76f5acc> x anonim
Офлайн
Вот вариант с декоратором
_IMPLEMENTATIONS = {}
class Factory(object):
def __init__(self, implementation_selector):
self._implementation_selector = implementation_selector
@classmethod
def register_implementation(cls, implementation):
_IMPLEMENTATIONS.setdefault(cls.__name__, {})[
implementation.name] = implementation()
@classmethod
def method(cls, implementation_selector):
factory = cls(implementation_selector)
def wrapper(method):
def implement(*argv, **kw):
try:
return factory[method.__name__](*argv, **kw)
except KeyError:
return method(*argv, **kw)
return implement
return wrapper
def __call__(self):
return _IMPLEMENTATIONS[self.__class__.__name__][
self._implementation_selector()]
def __getattr__(self, name):
return getattr(self(), name)
__getitem__ = __getattr__
class Implementation(object):
name = None
class AvatarFactory(Factory):
'''Avatar'''
class GravatarImplementation(Implementation):
name = 'gravatar'
def get_avatar_path(self, user, size=48):
import hashlib, urllib
hash = hashlib.md5(user.email.lower()).hexdigest()
gravatar_url = 'http://www.gravatar.com/avatar/' + hash + '?'
gravatar_url += urllib.urlencode({'s':str(size)})
return gravatar_url
AvatarFactory.register_implementation(GravatarImplementation)
implementation = 'default'
def implementation_selector():
return implementation
class User(object):
def __init__(self, login, email):
self.login = login
self.email = email
@AvatarFactory.method(implementation_selector)
def get_avatar_path(self, size=48):
return '/static/avatars/%s/%d' % (self.login, size,)
user = User('login', 'test@example.com')
user2 = User('test2', 'test2@example.com')
print user.get_avatar_path()
print user2.get_avatar_path()
implementation = 'gravatar'
print user.get_avatar_path()
print user2.get_avatar_path()
/static/avatars/login/48
/static/avatars/test2/48
http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=48
http://www.gravatar.com/avatar/43b05f394d5611c54a1a9e8e20baee21?s=48
Офлайн
Как-то все усложнено слишком на мой взгляд.
Офлайн
Edмой вариант в 14 посте - прост, унаследовать от Base, и в любой момент прописать подмену…
Как-то все усложнено слишком на мой взгляд.
class User(Base):
...
_classes['User'] = MyUser
Отредактировано (Фев. 16, 2011 15:42:51)
Офлайн
o7412369815963Вариант бы мне подошел, но загвоздка в том, что изменять поведение базового класса должны разные части системы не знающие друг о друге.
мой вариант в 14 посте - прост, унаследовать от Base
Офлайн
zheromoпочти тоже самое, но без декораторов, + исходники класса User не трогаем:
Вот вариант с декоратором
def get_avatar_path(self, size=48):
import hashlib, urllib
hash = hashlib.md5(self.email.lower()).hexdigest()
gravatar_url = 'http://www.gravatar.com/avatar/' + hash + '?'
gravatar_url += urllib.urlencode({'s':str(size)})
return gravatar_url
class User(object):
def __init__(self, login, email):
self.login = login
self.email = email
def get_avatar_path(self, size=48):
return '/static/avatars/%s/%d' % (self.login, size,)
user = User('login', 'test@example.com')
user2 = User('test2', 'test2@example.com')
print user.get_avatar_path()
print user2.get_avatar_path()
User.get_avatar_path = get_avatar_path
print user.get_avatar_path()
print user2.get_avatar_path()
Офлайн
o7412369815963Вернулись к “грязному” хаку из первого поста.
почти тоже самое, но без декораторов, + исходники класса User не трогаем:
Офлайн