当方法装饰器替换 self 时,应该预料到什么副作用?

发布于 2024-08-18 20:16:30 字数 590 浏览 6 评论 0原文

我想执行一个方法,并在执行时传递原始 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

泪眸﹌ 2024-08-25 20:16:30

副本使得传递给装饰函数的“自身”是原始函数的浅表副本。装饰函数不能直接修改原始的“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?

演出会有结束 2024-08-25 20:16:30

正如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, that copy.copy makes a shallow copy and so (while self.__dict__ itself won't be modified) mutable objects can perfectly well get altered. Using copy.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 at self -- what if those methods were altering globals, for example?!-). Seem a very iffy proposition to me.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文