Python如何创建一个包装任何值的类

2024-04-26 11:50:16 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个Entity类:

class Entity(dict):
    pass

    def save(self):
        ...

我可以用Entity(dict_obj)包装dict对象

但是有没有可能创建一个类来包装任何类型的对象,比如int,list等等

PS我提出了以下解决方法,它不适用于更复杂的对象,但似乎适用于基本对象,完全不确定是否有任何缺陷,可能会因为每次创建类而受到效率的惩罚,请让我知道:

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)

Tags: 对象selfobjgetreturnsavedefpass
1条回答
网友
1楼 · 发布于 2024-04-26 11:50:16

您提出的解决方案看起来很优雅,但缺少缓存,例如,每次调用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

相关问题 更多 >