Python 如何使类装饰器不破坏isinstance函数?

Python 如何使类装饰器不破坏isinstance函数?,python,python-3.x,singleton,decorator,Python,Python 3.x,Singleton,Decorator,我正在为测试创建一个单例装饰器,但当我询问一个对象是否是原始类的实例时,它返回false 在这个例子中,我装饰了一个计数器类来创建一个单例,所以每次我得到这个值时,不管对象的哪个实例调用它,它都会返回下一个数字。 代码非常有效,但函数isinstance似乎有问题,我尝试使用functools.update\u包装器,但我不知道是否可以让isinstance函数将Singleton识别为计数器(在下面的代码中),只要我请求计数器时,代码实际返回Singleton 室内装修设计师 装饰班 测试 输

我正在为测试创建一个单例装饰器,但当我询问一个对象是否是原始类的实例时,它返回false

在这个例子中,我装饰了一个计数器类来创建一个单例,所以每次我得到这个值时,不管对象的哪个实例调用它,它都会返回下一个数字。 代码非常有效,但函数isinstance似乎有问题,我尝试使用functools.update\u包装器,但我不知道是否可以让isinstance函数将Singleton识别为计数器(在下面的代码中),只要我请求计数器时,代码实际返回Singleton

室内装修设计师 装饰班 测试 输出:

#1 - [2, 3, 4, 5, 6, 0, 1, 2, 3, 4]
#2 - [5, 6, 0, 1, 2]
#3 - [3, 4, 5, 6, 0, 1, 2]
#4 - <class '__main__.singleton.<locals>.Singleton'>
#5 - <class '__main__.Counter'>
#6 - False
#1-[2,3,4,5,6,0,1,2,3,4]
#2 - [5, 6, 0, 1, 2]
#3 - [3, 4, 5, 6, 0, 1, 2]
#4 - 
#5 - 
#6-错误
(更新包装未注释)

#1-[2,3,4,5,6,0,1,2,3,4]
#2 - [5, 6, 0, 1, 2]
#3 - [3, 4, 5, 6, 0, 1, 2]
#4 - 
#5 - 
#6-错误
您可以在中使用类装饰器

它之所以有效,是因为它修改了现有类(替换了
\uuuu new\uuuu()
方法),而不是像您在问题代码中所做的那样,用一个完全独立的类替换它

import functools

# from https://wiki.python.org/moin/PythonDecoratorLibrary#Singleton
def singleton(cls):
    ''' Use class as singleton. '''

    cls.__new_original__ = cls.__new__

    @functools.wraps(cls.__new__)
    def singleton_new(cls, *args, **kw):
        it =  cls.__dict__.get('__it__')
        if it is not None:
            return it

        cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
        it.__init_original__(*args, **kw)
        return it

    cls.__new__ = singleton_new
    cls.__init_original__ = cls.__init__
    cls.__init__ = object.__init__

    return cls
通过它,我得到以下输出(注意最后一行):

[2,3,4,5,6,0,1,2,3,4]
[5, 6, 0, 1, 2]
[3, 4, 5, 6, 0, 1, 2]
真的

不比上述方法好,但如果您以后需要从内存中执行此操作,则更简单、更容易记住:

def singleton(Class, *initargs, **initkwargs):
    __instance = Class(*initargs, **initkwargs)
    Class.__new__ = lambda *args, **kwargs: __instance
    Class.__init__ = lambda *args, **kwargs: None
    return Class

在Python2上,如果您说
classsingleton(class)
,它就会起作用。不知道为什么它在Python3上不起同样的作用,但也许这可以引导你达到这个目的?我已经尝试过从类、对象和各种(如果不是全部)两者的组合继承,其中任何一种似乎都能起作用x.x这似乎是一个更聪明的想法,但为什么这段代码需要切换init函数,我注意到,如果删除此更改,第三行将重置。我想知道为什么会发生这种情况?克斯特尼亚:对不起,我不明白你所说的“第三行重置”是什么意思。我只是想这可能是因为init将在new之后调用,所以这基本上避免了对原始init的召回,对吗?它不再从[3,4,5…]开始,而是重新开始[0,1,2…]@martineau这是因为我在“Singleton.\uu instance=class()”处实例化了这个类。但是我理解需要删除原始的new和init,以确保它们也只被调用一次。事实上,这看起来是个好办法。不做
functools
包装,但在我看来这不是一个严重的限制-我想这只是一个小小的权衡。
#1 - [2, 3, 4, 5, 6, 0, 1, 2, 3, 4]
#2 - [5, 6, 0, 1, 2]
#3 - [3, 4, 5, 6, 0, 1, 2]
#4 - <class '__main__.singleton.<locals>.Singleton'>
#5 - <class '__main__.Counter'>
#6 - False
#1 - [2, 3, 4, 5, 6, 0, 1, 2, 3, 4]
#2 - [5, 6, 0, 1, 2]
#3 - [3, 4, 5, 6, 0, 1, 2]
#4 - <class '__main__.Counter'>
#5 - <class '__main__.Counter'>
#6 - False
import functools

# from https://wiki.python.org/moin/PythonDecoratorLibrary#Singleton
def singleton(cls):
    ''' Use class as singleton. '''

    cls.__new_original__ = cls.__new__

    @functools.wraps(cls.__new__)
    def singleton_new(cls, *args, **kw):
        it =  cls.__dict__.get('__it__')
        if it is not None:
            return it

        cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
        it.__init_original__(*args, **kw)
        return it

    cls.__new__ = singleton_new
    cls.__init_original__ = cls.__init__
    cls.__init__ = object.__init__

    return cls
def singleton(Class, *initargs, **initkwargs):
    __instance = Class(*initargs, **initkwargs)
    Class.__new__ = lambda *args, **kwargs: __instance
    Class.__init__ = lambda *args, **kwargs: None
    return Class