与此问题类似,我想替换一个属性.与那个问题不同,我不想在子类中覆盖它.我想在init和属性本身中替换它以提高效率,这样它就不必调用每次调用属性时计算值的函数.
我有一个课程,里面有一个属性.构造函数可以获取属性的值.如果传递了值,我想用值替换属性(不只是设置属性).这是因为属性本身会计算该值,这是一项昂贵的操作.类似地,我想用属性计算的值替换属性,以便将来对属性的调用不必重新计算:
class MyClass(object):
def __init__(self, someVar=None):
if someVar is not None: self.someVar = someVar
@property
def someVar(self):
self.someVar = calc_some_var()
return self.someVar
Run Code Online (Sandbox Code Playgroud)
上面的代码不起作用,因为执行self.someVar =不会替换someVar函数.它试图调用属性的setter,它没有定义.
我知道我可以用稍微不同的方式实现同样的目的:
class MyClass(object):
def __init__(self, someVar=None):
self._someVar = someVar
@property
def someVar(self):
if self._someVar is None:
self._someVar = calc_some_var()
return self._someVar
Run Code Online (Sandbox Code Playgroud)
这将略微降低效率,因为每次调用属性时都必须检查None.该应用程序对性能至关重要,因此这可能会或可能不够好.
有没有办法替换类实例上的属性?如果我能够做到这一点会有多高效(即避免无检查和函数调用)?
unu*_*tbu 15
您正在寻找的是Denis Otkidach优秀的CachedAttribute:
class CachedAttribute(object):
'''Computes attribute value and caches it in the instance.
From the Python Cookbook (Denis Otkidach)
This decorator allows you to create a property which can be computed once and
accessed many times. Sort of like memoization.
'''
def __init__(self, method, name=None):
# record the unbound-method and the name
self.method = method
self.name = name or method.__name__
self.__doc__ = method.__doc__
def __get__(self, inst, cls):
# self: <__main__.cache object at 0xb781340c>
# inst: <__main__.Foo object at 0xb781348c>
# cls: <class '__main__.Foo'>
if inst is None:
# instance attribute accessed on class, return self
# You get here if you write `Foo.bar`
return self
# compute, cache and return the instance's attribute value
result = self.method(inst)
# setattr redefines the instance's attribute so this doesn't get called again
setattr(inst, self.name, result)
return result
Run Code Online (Sandbox Code Playgroud)
它可以像这样使用:
def demo_cache():
class Foo(object):
@CachedAttribute
def bar(self):
print 'Calculating self.bar'
return 42
foo=Foo()
print(foo.bar)
# Calculating self.bar
# 42
Run Code Online (Sandbox Code Playgroud)
请注意,访问foo.bar后续时间不会调用getter函数.(Calculating self.bar不打印.)
print(foo.bar)
# 42
foo.bar=1
print(foo.bar)
# 1
Run Code Online (Sandbox Code Playgroud)
删除foo.bar从foo.__dict__重新暴露在中定义的属性Foo.因此,foo.bar再次调用再次重新计算该值.
del foo.bar
print(foo.bar)
# Calculating self.bar
# 42
demo_cache()
Run Code Online (Sandbox Code Playgroud)
装饰器发布在Python Cookbook中,也可以在ActiveState上找到.
这是有效的,因为虽然属性存在于类中__dict__,但在计算之后,在实例中创建了同名属性__dict__.Python的属性查找规则优先于实例中的属性__dict__,因此类中的属性会被有效覆盖.
| 归档时间: |
|
| 查看次数: |
1183 次 |
| 最近记录: |