我正在创建用于测试的单例装饰器,但是当我问一个对象是否属于原始类的实例时,它将返回false。
在该示例中,我正在装饰一个计数器类以创建一个单例,因此,每次获取值时,无论对象的任何实例调用它,它都会返回下一个数字。 代码几乎可以工作,但是功能isinstance似乎坏了,我尝试使用functools.update_wrapper,但我不知道只要我请求Counter,是否可以通过isinstance函数将Singleton识别为Counter(在以下代码中)该代码实际上返回Singleton。
def singleton(Class):
class Singleton:
__instance = None
def __new__(cls):
if not Singleton.__instance:
Singleton.__instance = Class()
return Singleton.__instance
#update_wrapper(Singleton, Class,
# assigned=('__module__', '__name__', '__qualname__', '__doc__', '__annotation__'),
# updated=()) #doesn't seems to work
return Singleton
@singleton
class Counter:
def __init__(self):
self.__value = -1
self.__limit = 6
@property
def value(self):
self.__value = (self.__value + 1) % self.limit
return self.__value
@property
def limit(self):
return self.__limit
@limit.setter
def limit(self, value):
if not isinstance(value, int):
raise ValueError('value must be an int.')
self.__limit = value
def reset(self):
self.__value = -1
def __iter__(self):
for _ in range(self.limit):
yield self.value
def __enter__(self):
return self
def __exit__(self,a,b,c):
pass
counter = Counter()
counter.limit = 7
counter.reset()
[counter.value for _ in range(2)]
with Counter() as cnt:
print([cnt.value for _ in range(10)]) #1
print([counter.value for _ in range(5)]) #2
print([val for val in Counter()]) #3
print(Counter) #4
print(type(counter)) #5
print(isinstance(counter, Counter)) #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 - <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
答案 0 :(得分:1)
您可以在singleton
中使用Python Decorator Library类装饰器。
之所以起作用,是因为它修改了现有的类(代替了__new__()
方法),而不是像问题代码中那样用完全独立的类替换它。
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]
<class '__main__.Counter'>
<class '__main__.Counter'>
True
答案 1 :(得分:1)
并不比上面更好,但是如果以后需要从内存中执行此操作,则稍微更容易记住:
def singleton(Class, *initargs, **initkwargs):
__instance = Class(*initargs, **initkwargs)
Class.__new__ = lambda *args, **kwargs: __instance
Class.__init__ = lambda *args, **kwargs: None
return Class