替换属性以获得性能增益
情况
类似于这个问题,我想要更换财产。与这个问题不同,我不想在子类中覆盖它。为了提高效率,我想在 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
问题
上面的代码不起作用,因为执行 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
这会稍微降低效率,因为每次调用该属性时都必须检查 None 。该应用程序对性能至关重要,因此这可能足够好,也可能不够好。
问题
有没有办法替换类实例上的属性?如果我能够做到这一点(即避免 None 检查和函数调用),效率会高多少?
Situation
Similar to this question, I want to replace a property. Unlike that question, I do not want to override it in a sub-class. I want to replace it in the init and in the property itself for efficiency, so that it doesn't have to call a function which calculates the value each time the property is called.
I have a class which has a property on it. The constructor may take the value of the property. If it is passed the value, I want to replace the property with the value (not just set the property). This is because the property itself calculates the value, which is an expensive operation. Similarly, I want to replace the property with the value calculated by the property once it has been calculated, so that future calls to the property do not have to re-calculate:
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
Problem
The above code does not work because doing self.someVar = does not replace the someVar function. It tries to call the property's setter, which is not defined.
Potential Solution
I know I can achieve the same thing in a slightly different way as follows:
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
This will be marginally less efficient as it will have to check for None every time the property is called. The application is performance critical, so this may or may not be good enough.
Question
Is there a way to replace a property on an instance of a class? How much more efficient would it be if I was able to do this (i.e. avoiding a None check and a function call)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您正在寻找的是Denis Otkidach的优秀CachedAttribute:
它可以像这样使用:
注意访问< code>foo.bar 随后的时间不会调用getter函数。 (
计算 self.bar
不会被打印。)从
foo.__dict__
中删除foo.bar
会重新公开Foo 中定义的属性
。因此,再次调用 foo.bar 会再次重新计算该值。
该装饰器发布在 Python Cookbook 中,也可以在 活动状态。
这是高效的,因为虽然该属性存在于类的 __dict__ 中,但在计算之后,会在实例的 __dict__ 中创建同名的属性。 Python 的属性查找规则优先考虑实例的 __dict__ 中的属性,因此类中的属性会被有效地覆盖。
What you are looking for is Denis Otkidach's excellent CachedAttribute:
It can be used like this:
Notice that accessing
foo.bar
subsequent times does not call the getter function. (Calculating self.bar
is not printed.)Deleting
foo.bar
fromfoo.__dict__
re-exposes the property defined inFoo
.Thus, calling
foo.bar
again recalculates the value again.The decorator was published in the Python Cookbook and can also be found on ActiveState.
This is efficient because although the property exists in the class's
__dict__
, after computation, an attribute of the same name is created in the instance's__dict__
. Python's attribute lookup rules gives precedence to the attribute in the instance's__dict__
, so the property in class becomes effectively overridden.当然,您可以在类实例的私有字典中设置属性,该属性在调用属性函数
foo
之前优先(位于静态字典A.__dict__
中)如果您想再次重置以处理该属性,只需
del self.__dict__['foo']
Sure, you can set the attribute in the private dictionary of the class instance, which takes precedence before calling the property function
foo
(which is in the static dictionaryA.__dict__
)If you want to reset again to work on the property, just
del self.__dict__['foo']
这与 Denis Otkidach 的 CachedAttribute 基本相同,但稍微更健壮,因为它允许:
或
This is basically the same as Denis Otkidach's
CachedAttribute
, but slightly more robust in that it allows either:or
您可以通过替换函数的
来更改函数的代码 >__code__
对象与来自另一个函数的__code__
对象。这是我创建的一个装饰器函数来为您完成此任务。请随意修改您认为合适的内容。但要记住的重要一点是,这两个函数需要具有相同数量的“自由变量”才能像这样交换。通过使用 nonlocal 来强制执行此操作可以轻松完成(如下所示)。
You can change what code a function has by replacing the functions's
__code__
object with the__code__
object from another function.Here is a decorator function that I created to do just that for you. Feel free to modify it as you see fit. The big thing to remember though is that the both functions need to have the same number of 'free variables' to be swapped like this. This can easily be done by using nonlocal to force it (as shown below).