Python “装饰师”;对象不可调用";
我试图掌握Python中的decorator,并试图从botocore库中实现一个版本的Python “装饰师”;对象不可调用";,python,python-3.x,python-decorators,callable-object,Python,Python 3.x,Python Decorators,Callable Object,我试图掌握Python中的decorator,并试图从botocore库中实现一个版本的CachedPropertydecorator,但一直遇到一个错误: TypeError:“CachedProperty”对象不可调用 今天我在谷歌上搜索了一段时间,但我发现的例子似乎与我的问题没有直接的对应关系。它们主要与试图调用int和failing等对象的人有关 当我单步执行代码时,decorator在导入sum\u args()时在CachedPropertyok中调用\uu init\uuuuuuu
CachedProperty
decorator,但一直遇到一个错误:
TypeError:“CachedProperty”对象不可调用
今天我在谷歌上搜索了一段时间,但我发现的例子似乎与我的问题没有直接的对应关系。它们主要与试图调用int和failing等对象的人有关
当我单步执行代码时,decorator在导入sum\u args()
时在CachedProperty
ok中调用\uu init\uuuuuuuuuuuuuuuuuuuuuuuuu>,但在我从单元测试调用函数本身时抛出一个错误
我的单元测试:
import unittest
from decorators.caching_example import sum_args
class TestCachedProperty(unittest.TestCase):
def test_sum_integers(self):
data = [1, 2, 3]
result = sum_args(data)
self.assertEqual(result, 6)
我试图装饰的功能:
from decorators.caching_property import CachedProperty
@CachedProperty
def sum_args(arg):
total = 0
for val in arg:
total += val
return total
我从botocore中提升的CachedProperty
类:
class CachedProperty(object):
"""A read only property that caches the initially computed value.
This descriptor will only call the provided ``fget`` function once.
Subsequent access to this property will return the cached value.
"""
def __init__(self, fget):
self._fget = fget
def __get__(self, obj, cls):
if obj is None:
return self
else:
computed_value = self._fget(obj)
obj.__dict__[self._fget.__name__] = computed_value
return computed_value
查看我最初使用的程序,我希望它将sum函数传递给CachedProperty
类–在运行时创建一个实例–并将结果存储在其内部实例变量self.\u fget
我实际上得到的是:
错误
回溯(最近一次呼叫最后一次):
testPartExecutor中的文件“/usr/local/ceral/python/3.7.3/Frameworks/python.framework/Versions/3.7/lib/python3.7/unittest/case.py”,第59行
产量
文件“/usr/local/ceral/python/3.7.3/Frameworks/python.framework/Versions/3.7/lib/python3.7/unittest/case.py”,第615行,正在运行
testMethod()
文件“/Users/bradley.atkins/PycharmProjects/brad/examples/tests/decorators/test_property_cache.py”,第11行,在test_sum_integers中
结果=总和参数(数据)
TypeError:“CachedProperty”对象不可调用
您的sum_参数
被评估为缓存属性
,该属性不实现任何\u调用
方法,因此不可调用。这就是为什么当您尝试使用sum_args(data)
尝试将代码更改为:
class CachedProperty(object):
def __init__(self, fget):
self._fget = fget
def __call__(self, obj):
if obj is None:
return obj
else:
computed_value = self._fget(obj)
self.__dict__[self._fget.__name__] = computed_value
return computed_value
@CachedProperty
def sum_args(arg):
total = 0
for val in arg:
total += val
return total
data = [1, 2, 3]
result = sum_args(data)
print(result) # >> 6
CachedProperty
,如其名称所述,是指用作类主体(不是独立函数)中方法的装饰器,然后这些方法的行为将类似于普通Python的“属性”,但它们是“缓存的”。-)
在您的示例代码中,您试图将其应用于模块级函数,但这不起作用-因为此装饰程序将函数转换为依赖于仅对类成员有效的属性访问机制(即“描述符协议”)的对象,它适用于在\uuuuuu get\uuuuuuuuuuuuuuuuuuuu
、\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu设置
或\uu
实际上,Python中的装饰器非常简单——它没有特殊情况。代码中明显的“特殊情况”是由于返回对象的性质造成的
因此,简而言之-装饰器只是一个可调用的对象,它接受一个单独的参数,这是另一个可调用的参数-通常是一个函数或一个类,并返回另一个对象(不一定可调用),该对象将替换第一个
因此,给出一个简单的装饰器,例如:
def logcalls(func):
def wrapper(*args, **kw):
print(f"{func} called with {args} and {kw}")
return func(*args, **kw)
return wrapper
它可以用作:
@logcalls
def add(a, b):
return a + b
这相当于:
def add(a, b):
return a + b
add = logcalls(a + b)
就这么简单
当您想要为装饰器传递额外的参数时,可能会出现复杂性,然后您需要有一个“阶段”来接受这些配置参数,并返回一个可调用的,将装饰对象作为其单个参数。在一些代码库中,导致装饰器由3层嵌套函数组成,这可能会让人难以理解
如果上面的CachedProperty
将实现一个\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
方法,那么除了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu获取。另外,值得注意的是,对于对普通函数的缓存调用,Python的标准库在模块-functools.lru\u cache()
中确实有一个修饰符。感谢Olinox,这并不是我想要的,因为如果我用不同的值再次调用它,我会得到这些值的总和,而不是缓存的结果。正如jsbueno在下面指出的,我完全没有注意到这应该缓存类的属性。所以我现在正专注于这一点。但是,谢谢,你在可调用调用语法方面做得很好。谢谢jsbueno,你说的很有道理。可调的是,我不认为我今天有一个非常清醒的一天,所以明天会回到这一点上。:)谢谢你的帮助和指出我明显的错误。。。