Найти - Пользователи
Полная версия: Обратное наследование
Начало » Python для экспертов » Обратное наследование
1 2 3 4 5
zheromo
Всем спасибо.

Вариант с фабрикой также придется дополнить методом регистрации новой реализации.
Накидал небольшой прототип.

_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()
implementation_selector выбирает текущую реализацию, например по параметру из конфига или еще откуда

И останется решить еще один вопрос, так как методов в User много, то придется выбрать из вариантов:

1. создавать по фабрике на каждый чих
class User(object):
avatar = AvatarFactory(...)
amount = AmountFactory(...)
gender = GenderFactory(...)
some_future = SomeFutureFactory(...)
...
2. использовать стратегию, но потеряется гибкость в плане того, что разные методы должны меняться из разных мест

Как вариант возникла идея создания декоратора который будет помечать метод, как имеющий возможность заменяться фабрикой, его реализация и будет дефолтной, и будет возможность зарегистрировать новые реализации для этого метода.

class AvatarFactory(Factory):
'''Avatar'''

class User(db.Model):

...
@factory(AvatarFactory):
def get_avatar_path(self, size=48):
return 'default path'
o7412369815963
А если класс User переименовать в BaseUser, и приравнять User = BaseUser, а потом когда надо переопределить?

А в своем толстом проекте я сделал глобальный метод, который раздавал мне экземпляры классов в зависимости от параметров:
user = getObject('User',params)
PooH
У меня какое-то смутное ощущение, что я наблюдаю торжество проектировщика над здравым смыслом. Может быть я и не прав.
o7412369815963
Вот такой можно фокус сделать - при создании экземпляра класса 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
zheromo
Вот вариант с декоратором

_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
Как-то все усложнено слишком на мой взгляд.
o7412369815963
Ed
Как-то все усложнено слишком на мой взгляд.
мой вариант в 14 посте - прост, унаследовать от Base, и в любой момент прописать подмену…
class User(Base):
...
_classes['User'] = MyUser
ЗЫ: использую словарь _classes для того что-б можно было подменять несколько(все) классов(ы)
zheromo
o7412369815963
мой вариант в 14 посте - прост, унаследовать от Base
Вариант бы мне подошел, но загвоздка в том, что изменять поведение базового класса должны разные части системы не знающие друг о друге.
o7412369815963
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()
zheromo
o7412369815963
почти тоже самое, но без декораторов, + исходники класса User не трогаем:
Вернулись к “грязному” хаку из первого поста.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB