gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 01:06:04 24 4
gpt4 key购买 nike

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

在示例中,我正在装饰一个计数器类来创建一个单例,因此每次获得值时,无论对象的哪个实例调用它,它都会返回下一个数字。代码几乎可以工作,但函数 isinstance 似乎中断了,我尝试使用 functools.update_wrapper 但我不知道是否可以让 isinstance 函数将 Singleton 识别为 Counter(在下面的代码中),只要当我要求 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

最佳答案

您可以使用 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

关于python - 如何使类装饰器不破坏 isinstance 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55345243/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com