当方法装饰器替换 self 时,应该预料到什么副作用?
我想执行一个方法,并在执行时传递原始 self
的副本。
这是我正在讨论的代码:
def protect_self(func):
from copy import copy
from functools import wraps
@wraps(func)
def decorated(self, *args, **kwargs):
self_copy = copy(self)
return func(self_copy, *args, **kwargs)
return decorated
根据我的理解,复制函数创建一个相同类型的新对象,并且 将旧对象的 __dict__ 复制到新对象(使用引用,因此 对 __dict__ 中实际对象实例的更改仍会影响原始对象)。
这是否意味着我可以确定装饰方法不能修改 __dict__ 原始实例?
只是为了确保:我不需要安全的沙箱行为。我的目的只是 实例化一个对象,我将其用作工厂。这 protected 方法应该可以修改传递的 self
但它应该 之后会被重置。
I want to execute a method with a copy of the original self
passed while execution.
Here is the code I'm talking about:
def protect_self(func):
from copy import copy
from functools import wraps
@wraps(func)
def decorated(self, *args, **kwargs):
self_copy = copy(self)
return func(self_copy, *args, **kwargs)
return decorated
In my understanding the copy function creates a new object of the same type and
copies the __dict__
of the old one to the new object (using references, so
changes to actual object instances in __dict__
will still affect the original object).
Does this mean I can be sure that the decorated method cannot modify __dict__
of
the original instance?
Just to make sure: I don't need a secure sandbox behaviour. My purpose is just
to have a single object instanciated which I will use as a factory. The
protected method should be possible to modify the passed self
but it should
be reseted afterwards.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
副本使得传递给装饰函数的“自身”是原始函数的浅表副本。装饰函数不能直接修改原始的“self”,尽管它当然可以通过其他方式修改它(如果它可以间接访问它)。如果对象的任何属性是可变的,它可以有效地改变对象的属性。通过修改属性来恢复原来的“自我”。
此外,任何(任意)Python 代码都可以间接访问程序中的几乎任何对象。例如,修饰函数可以通过堆栈检查或通过 gc 模块来访问原始“自身”。你的用例看起来有点复杂;您确定应该为此使用类实例吗?
The copy makes it so the 'self' passed to the decorated function is a shallow copy of the original. The decorated function can't modify the original 'self' directly, although it can of course modify it through other means (if it has indirect access to it.) If any of the attributes of the object are mutable, it can effectively change the original 'self' by modifying the attributes.
Additionally, any piece of (arbitrary) Python code has indirect access to pretty much any object in the program. The decorated function could gain access to the original 'self' through stack inspection, or through the
gc
module, for example. Your usecase seems a little convoluted; are you sure you should be using a class instance for this?正如OP在评论中澄清的那样,目的是线程安全的,那么除了这个问题之外,还有一个明显的问题——
copy.copy
本身不是线程安全的已经指出,copy.copy
会进行浅复制,因此(而self.__dict__
本身不会被修改)可变对象可以完全可以改变。使用copy.deepcopy可以解决这个问题(在性能方面可能会付出高昂的代价),但在某种意义上甚至会恶化线程安全问题(因为深复制可能比浅复制花费更长的时间)复制时,竞争条件实际发生的风险会突飞猛进 - 并不是说我以任何方式、形式或形式建议出现“很少”发生的竞争条件,请注意!- )。如果您必须使原本不安全的方法成为线程安全的,您将不得不硬着头皮使用锁(或队列和辅助线程来序列化操作)——我想如果您进一步需要默默地忽略方法尝试更改对象,而且您还必须
深层复制
所有内容(为什么停在self
处——如果这些方法正在更改全局怎么办? , 例如?!-)。对我来说这似乎是一个非常不确定的提议。As the OP clarified in a comment that the purpose is to be threadsafe, then there's an obvious issue --
copy.copy
itself isn't threadsafe, in addition to the issue already pointed out, thatcopy.copy
makes a shallow copy and so (whileself.__dict__
itself won't be modified) mutable objects can perfectly well get altered. Usingcopy.deepcopy
deals with this (at a potentially hefty price in terms of performance) but in a sense even worsens the issue of thread-safety (since deep-copying can take so much longer than shallow-copying, the risk of a race condition actually occurring grows by leaps and bounds -- not that I'm in any way, shape or form recommending having race conditions that occur "only rarely", mind!-).If you have to make originally-unsafe methods thread-safe, you'll have to bite the bullet and use locks (or a Queue and an auxiliary thread to serialize the operations) -- I guess that if you further need to silently ignore the methods' attempts to alter objects, you'll moreover have to
deepcopy
everything (why stop atself
-- what if those methods were altering globals, for example?!-). Seem a very iffy proposition to me.