在类“主要缺陷”中实现装饰器?

2024-04-19 11:20:17 发布

您现在位置:Python中文网/ 问答频道 /正文

为什么这个装饰策略被认为是不好的?(……还是!?)你知道吗

class User(object):

    def __init__(self):
        self.thing = 5

    def __atomic_rate_change(fn):
        def wrapper(self,*args,**kwargs):
            print "start magic"
            self.thing += 1
            fn(self,*args,**kwargs)
            print "end magic"
        return wrapper

    @__atomic_rate_change
    def foo(self,add):
        print self.__atomic_rate_change # <bound method User.__atomic_rate_change of <__main__.User object at 0x6ffffe1ef50>>
        self.thing += add
        print "normal call {0}".format(self.thing)

test = User()
test.foo(1)

这很管用。但是,根据下面的资料,这是不好的做法。原因是:

[...] there is major flaw in this approach: atomic_rating_change becomes an instance method of the User class. That doesn’t make any sense. More than this, it doesn’t even work as a method: if you call it, the decorated parameter will be used as self.

https://medium.com/@vadimpushtaev/decorator-inside-python-class-1e74d23107f6

我不明白为什么原子速率变化是一个实例方法是一个问题/错误/坏。我只打算在课堂上使用装饰器。也许在这种情况下没关系?你知道吗


Tags: selfobjectratedefargs装饰changewrapper
1条回答
网友
1楼 · 发布于 2024-04-19 11:20:17

从风格上讲,将函数定义放在类定义中而不是方法有点不合时宜(我认为它甚至可能是非语法的)。Flat is better than nested,所以最好在类之外声明函数。这样,当读者在查看您的类时,就不会混淆为什么会有一个方法,它不以self作为参数(因为当函数仅仅是一个装饰器时,它被声明为一个方法,尽管如果函数是@staticmethod,这会略有不同)。你知道吗

如果您担心它在类之外被使用,请在它前面加上_前缀,然后from my_package import *就不会导入它了。它仍然可以在该模块中使用,但除非显式导入,否则不会在外部使用。你知道吗

实际上,作者指的是偶尔出现的奇怪的作用域行为(类似于Javascript中关于是根据事物的作用域来使用function() { ...还是() => { ...的争论)。如果您不小心,并且不小心在decorator的错误部分包含了self的逻辑,则可能会出现作用域问题。你知道吗

我能看到的在类中使用函数的唯一优点可能是因为它更接近方法(但这会引入不必要的嵌套、潜在的作用域问题以及认识到这是一个装饰器而不是一个方法的认知负载),并且如果函数的名称是从___开始的,则可以更好地隐藏函数。你知道吗

TL;DR风格/Pythonicity问题,以及潜在的范围界定问题。你知道吗

相关问题 更多 >