Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使iInstance(obj、cls)与装饰类一起工作_Python_Class_Python 2.7_Python Decorators - Fatal编程技术网

Python 使iInstance(obj、cls)与装饰类一起工作

Python 使iInstance(obj、cls)与装饰类一起工作,python,class,python-2.7,python-decorators,Python,Class,Python 2.7,Python Decorators,我有几个课程需要做以下工作: 调用构造函数时,如果已经存在相等的对象(即具有相同id的对象),则返回该对象。否则,创建一个新实例。 基本上 >>> cls(id=1) is cls(id=1) True 为了实现这一点,我编写了一个类装饰器,如下所示: class Singleton(object): def __init__(self, cls): self.__dict__.update({'instances': {},

我有几个课程需要做以下工作:

调用构造函数时,如果已经存在相等的对象(即具有相同id的对象),则返回该对象。否则,创建一个新实例。 基本上

>>> cls(id=1) is cls(id=1)
True
为了实现这一点,我编写了一个类装饰器,如下所示:

class Singleton(object):
    def __init__(self, cls):
        self.__dict__.update({'instances': {},
                                'cls': cls})

    def __call__(self, id, *args, **kwargs):
        try:
            return self.instances[id]
        except KeyError:
            instance= self.cls(id, *args, **kwargs)
            self.instances[id]= instance
            return instance

    def __getattr__(self, attr):
        return getattr(self.cls, attr)
    def __setattr__(self, attr, value):
        setattr(self.cls, attr, value)
这正是我想要的,但是:

@Singleton
class c(object):
    def __init__(self, id):
        self.id= id

o= c(1)
isinstance(o, c) # returns False
我怎样才能解决这个问题?我找到了一个解决方案,但我似乎无法使这些解决方案适应我的用例


我知道有人会让我发布一些不起作用的代码,所以给你:

def Singleton(cls):
    instances= {}
    class single(cls):
        def __new__(self, id, *args, **kwargs):
            try:
                return instances[id]
            except KeyError:
                instance= cls(id, *args, **kwargs)
                instances[id]= instance
                return instance
    return single
# problem: isinstance(c(1), c) -> False

def Singleton(cls):
    instances= {}
    def call(id, *args, **kwargs):
        try:
            return instances[id]
        except KeyError:
            instance= cls(id, *args, **kwargs)
            instances[id]= instance
            return instance
    return call
# problem: isinstance(c(1), c) -> TypeError
您可以在decorator类中添加自定义挂钩:

def __instancecheck__(self, other):
    return isinstance(other, self.cls)

作为使用装饰器生成单例类的替代方案,您可以使用元类来创建类。元类可以用于向类添加功能,就像子类可以从其超类中继承功能一样。元类的优点是名称
c
实际上直接引用类
c
,而不是
Singleton
对象或包装对
c
构造函数调用的函数

例如:

class SingletonMeta(type):
    """SingletonMeta is a class factory that adds singleton functionality to a 
    class. In the following functions `cls' is the actual class, not 
    SingletonMeta."""

    def __call__(cls, id, *args, **kwargs):
        """Try getting a preexisting instance or create a new one"""
        return cls._instances.get(id) or cls._new_instance(id, args, kwargs)

    def _new_instance(cls, id, args, kwargs):
        obj = super(SingletonMeta, cls).__call__(*args, **kwargs)
        assert not hasattr(obj, "id"), "{} should not use 'id' as it is " \
            "reserved for use by Singletons".format(cls.__name__)
        obj.id = id
        cls._instances[id] = obj
        return obj        

    def __init__(cls, classname, bases, attributes):
        """Used to initialise `_instances' on singleton class"""
        super(SingletonMeta, cls).__init__(classname, bases, attributes)    
        cls._instances = {}
你这样使用它:

# python 2.x
class MySingleton(object):
    __metaclass__ = SingletonMeta

# python 3.x
class MySingleton(object, metaclass=SingletonMeta):
    pass
与您的装饰师比较使用:

class IDObject(object):
    def __str__(self):
        return "{}(id={})".format(type(self).__name__, self.id)

@Singleton
class A(IDObject):
    def __init__(self, id):
        self.id = id

class B(IDObject, metaclass=SingletonMeta):
    pass

format_str = """{4} class is {0}
an instance: {1}
{1} is {1} = {2}
isinstance({1}, {0.__name__}) = {3}"""
print(format_str.format(A, A(1), A(1) is A(1), isinstance(A(1), A), "decorator"))
print()
print(format_str.format(B, B(1), B(1) is B(1), isinstance(B(1), B), "metaclass"))
产出:

decorator class is <__main__.Singleton object at 0x7f2d2dbffb90>
an instance: A(id=1)
A(id=1) is A(id=1) = True
isinstance(A(id=1), A) = False

metaclass class is <class '__main__.B'>
an instance: B(id=1)
B(id=1) is B(id=1) = True
isinstance(B(id=1), B) = True
decorator类是
一个实例:A(id=1)
A(id=1)是A(id=1)=真
isinstance(A(id=1),A)=False
元类类是
一个实例:B(id=1)
B(id=1)是B(id=1)=真
isinstance(B(id=1),B)=真

我自己并没有对它进行过太多的调查,但有一篇关于“universal decorators”的10篇博文非常好。这是第一个。这里引用的收藏:给那些被否决的人:我很感谢你的评论。如果你不告诉我我做错了什么,我就不能提出更好的问题。@abarnert:为什么不试试呢?:)它将产生一个
运行时错误:超过了最大递归深度
,因为
\uuuu setattr\uuuu
试图检索
self.cls
@Rawing:Ah,对。通常我通过让
\uuuuu setattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;对象。setattr(self,'cls',cls)
,因为这尊重描述符协议。好吧,这是一个比我预期的简单得多的解决方案。非常感谢。