假设我有一个Entity
班:
class Entity(dict):
pass
def save(self):
...
我可以用Entity(dict_obj)
包裹字典对象
但是有可能创建一个可以包装任何类型对象的类,例如。 int,列表等。
我提出了以下解决方法,它不适用于更复杂的对象,但似乎可以与基本对象一起使用,完全不确定是否有陷阱,可能会因创建每个类而受到效率的影响。时间,请让我知道:
class EntityMixin(object):
def save(self):
...
def get_entity(obj):
class Entity(obj.__class__, EntityMixin):
pass
return Entity(obj)
用法:
>>> a = get_entity(1)
>>> a + 1
2
>>> b = get_entity('b')
>>> b.upper()
'B'
>>> c = get_entity([1,2])
>>> len(c)
2
>>> d = get_entity({'a':1})
>>> d['a']
1
>>> d = get_entity(map(lambda x : x, [1,2]))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/jlin/projects/django-rest-framework-queryset/rest_framework_queryset/entity.py", line 11, in get_entity
return Entity(obj)
TypeError: map() must have at least two arguments.
提高效率:
EntityClsCache = {}
class EntityMixin(object):
def save(self):
...
def _get_entity_cls(obj):
class Entity(obj.__class__, EntityMixin):
pass
return Entity
def get_entity(obj)
cls = None
try:
cls = EntityClsCache[obj.__class__]
except AttributeError:
cls = _get_entity_cls(obj)
EntityClsCache[obj.__class__] = cls
return cls(obj)
答案 0 :(得分:0)
您提出的解决方案看起来不错,但是它缺乏缓存,因为即使类型相同,每次调用get_entity()
时,您都将构造一个唯一的类。
Python具有元类,它们充当类工厂。鉴于元类的方法覆盖了类而不是实例的方法,我们可以实现类缓存:
class EntityMixin(object):
pass
class CachingFactory(type):
__registry__ = {}
# Instead of declaring an inner class,
# we can also return type("Wrapper", (type_, EntityMixin), {}) right away,
# which, however, looks more obscure
def __makeclass(cls, type_):
class Wrapper(type_, EntityMixin):
pass
return Wrapper
# This is the simplest form of caching; for more realistic and less error-prone example,
# better use a more unique/complex key, for example, tuple of `value`'s ancestors --
# you can obtain them via type(value).__mro__
def __call__(cls, value):
t = type(value)
typename = t.__name__
if typename not in cls.__registry__:
cls.__registry__[typename] = cls.__makeclass(t)
return cls.__registry__[typename](value)
class Factory(object):
__metaclass__ = CachingFactory
这样,Factory(1)
执行Factory.__call__(1)
,即CachingFactory.__call__(1)
(如果没有元类,那将是一个构造函数调用,这将导致一个类实例-但是我们想要首先创建一个类,然后实例化它。
我们可以确保Factory
创建的对象是同一类的实例,这是第一次为它们专门设计的:
>>> type(Factory(map(lambda x: x, [1, 2]))) is type(Factory([1]))
True
>>> type(Factory("a")) is type(Factory("abc"))
True