Форум сайта python.su
А так?
class Factory(object):
_IMPLEMENTATIONS = {}
def __init__(self, selector):
self.selector = selector
@classmethod
def register_implementation(cls, impl):
cls._IMPLEMENTATIONS[impl.im_class.name] = impl
def __getattr__(self, name):
return self._IMPLEMENTATIONS[self.selector(name)]
class DefaultAvatar:
name = 'default'
def get_avatar_path(self, user, size=48):
return '/static/avatars/%s/%d' % (user.login, size,)
class Gravatar:
name = 'gravatar'
def get_avatar_path(self, user, size=48):
return 'http://www.gravatar.com/avatar/bla-bla?'
implementation = 'default'
def implementation_selector(name):
return implementation
class User(object):
avatar = Factory(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)
# --------
defavatar = DefaultAvatar()
Factory.register_implementation(defavatar.get_avatar_path)
gravatar = Gravatar()
Factory.register_implementation(gravatar.get_avatar_path)
user1 = User('login', 'test@example.com')
user2 = User('test2', 'test2@example.com')
print user1.get_avatar_path()
print user2.get_avatar_path()
implementation = 'gravatar'
print user1.get_avatar_path()
print user2.get_avatar_path()
Офлайн
Согласен.
_IMPLEMENTATIONS лучше определить внутри класса фабрики.
Но __call__ __getattr__ лучше оставить, потому что в реализация может перекрывать больше чем один метод.
class Factory(object):
_IMPLEMENTATIONS = {}
def __init__(self, selector):
self.selector = selector
@classmethod
def register_implementation(cls, impl):
cls._IMPLEMENTATIONS[impl.name] = impl
def __call__(self):
return self._IMPLEMENTATIONS[self.selector(self.__class__)]
def __getattr__(self, name):
return getattr(self(), name)
class DefaultAvatar:
name = 'default'
def get_avatar_path(self, user, size=48):
return '/static/avatars/%s/%d' % (user.login, size,)
def get_avatar_something(self, user):
return 'something'
class Gravatar:
name = 'gravatar'
def get_avatar_path(self, user, size=48):
return 'http://www.gravatar.com/avatar/bla-bla?'
def get_avatar_something(self, user):
return 'gravatar'
implementation = 'default'
def implementation_selector(cls):
return implementation
class User(object):
avatar = Factory(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)
def get_avatar_something(self):
return self.avatar.get_avatar_something(self)
# --------
defavatar = DefaultAvatar()
Factory.register_implementation(defavatar)
gravatar = Gravatar()
Factory.register_implementation(gravatar)
user1 = User('login', 'test@example.com')
user2 = User('test2', 'test2@example.com')
print user1.get_avatar_path()
print user1.get_avatar_something()
print user2.get_avatar_path()
print user2.get_avatar_something()
implementation = 'gravatar'
print user1.get_avatar_path()
print user1.get_avatar_something()
print user2.get_avatar_path()
print user2.get_avatar_something()
BaseClass
/ / |
/ / |
/ / |
Imp1 Impl2 | --- Factory
\ \ |
\ \ |
\ \ |
ReallyUsedClass
class Factory(list):
def __init__(self, BaseClass):
self.name = BaseClass.__name__ + "Factory"
self = [BaseClass]
def __call__(self, *argv, **kw):
cls = type(self.name, tuple(reversed(self)), {})
return cls(*argv, **kw)
# ----
class _User(object):
def __init__(self, login, email):
self.login = login
self.email = email
def method(self):
return 'original method'
def get_avatar_path(self, size=48):
return '/static/avatars/%s/%d' % (self.login, size,)
def do_something(self):
return 'do something'
User = Factory(_User)
# ----
class GravatarUser(_User):
def get_avatar_path(self, size=48):
return '/gravatar!!!'
User.append(GravatarUser)
class SomethingUser(_User):
def do_something(self):
return 'new do something!!!'
User.append(SomethingUser)
# --- используем где-то там далеко ---
u = User('test', 'test@example.com')
print u.get_avatar_path(96)
print u.method()
print u.do_something()
Отредактировано (Фев. 16, 2011 22:11:10)
Офлайн
zheromoЛюбой каприз :)
Но __call__ __getattr__ лучше оставить, потому что в реализация может перекрывать больше чем один метод.
class Factory(object):
_IMPLEMENTATIONS = {}
def __init__(self, selector):
self.selector = selector
@classmethod
def register_implementation(cls, impl):
cls._IMPLEMENTATIONS[(impl.im_class.name, impl.__func__.__name__)] = impl
def __getattr__(self, name):
return self._IMPLEMENTATIONS[(self.selector(name), name)]
class DefaultAvatar:
name = 'default'
def get_avatar_path(self, user, size=48):
return '/static/avatars/%s/%d' % (user.login, size,)
def foo(self):
return 'default avatar foo'
class Gravatar:
name = 'gravatar'
def get_avatar_path(self, user, size=48):
return 'http://www.gravatar.com/avatar/bla-bla?'
def foo(self):
return 'gravatar foo'
implementation = 'default'
def implementation_selector(name):
return implementation
class User(object):
avatar = Factory(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)
def foo(self):
return self.avatar.foo()
# --------
defavatar = DefaultAvatar()
Factory.register_implementation(defavatar.get_avatar_path)
Factory.register_implementation(defavatar.foo)
gravatar = Gravatar()
Factory.register_implementation(gravatar.get_avatar_path)
Factory.register_implementation(gravatar.foo)
user1 = User('login', 'test@example.com')
user2 = User('test2', 'test2@example.com')
print user1.get_avatar_path()
print user2.get_avatar_path()
print user1.foo()
print user2.foo()
implementation = 'gravatar'
print user1.get_avatar_path()
print user2.get_avatar_path()
print user1.foo()
print user2.foo()
Офлайн
Идея с неявными манипуляциями с классами мне не нравится. Тоже как-то сложно выглядит и непонятно какая от нее польза. Explicit is better than implicit.
Офлайн
Формально код очень простой
class Factory(list):
def __init__(self, BaseClass):
self.name = BaseClass.__name__ + "Factory"
self = [BaseClass]
def __call__(self, *argv, **kw):
cls = type(self.name, tuple(reversed(self)), {})
return cls(*argv, **kw)
def user_factory(login, email):
class UserMixIn(SomethingUser, GravatarUser, User):
pass
user = UserMixIn(login, email)
return user
Офлайн
Слежу за вашей перепиской - и до сих пор ничего не понял.
Еще раз, простыми словами, объясните пожалуйста, что вы хотите сделать.
Вижу лишь занятные способы работы с классами, не более. Цель - ускользает от понимания.
Офлайн
Цель проста:
1. есть некий набор классов К который не меняется
2. часть системы А использует набор К инстанцируясь от него
3. другая часть системы Б должна изменить поведение классов К, так чтобы это отразилось на А
4. ни А ни Б о друг друге не знают
5. Б взаимодействует с К до того как А будет инстанцирована
Офлайн
Окончательная цель, как я понял - сделать механизм динамической замены одних методов на другие в зависимости от неких внешних условий.
В последних примерах в зависимости от переменной implementation во всех объектах класса User при вызове get_avatar_path()
будет вызываться либо DefaultAvatar().get_avatar_path, либо Gravatar().get_avatar_path.
Офлайн
EdАбсолютно верно
Окончательная цель, как я понял - сделать механизм динамической замены одних методов на другие в зависимости от неких внешних условий.
Офлайн
Стратегия бы вполне подошла, но суть в том, что динамическая замена одних методов на другие может производится из нескольких мест, т.е. требуется некая “смешанная” стратегия, а не просто выбор одной. Т.к. разные части кода могут менять разные методы.
Офлайн