类装饰器作用于类实例与类定义的差异及方法返回不同的原因
问题1:调用类装饰器作用于类实例和类定义之间有什么区别?
这两种用法的核心差异在于装饰器作用的对象完全不同,直接导致后续行为产生本质区别:
当用
@Deco('deco')作用于TestClassWrapped类定义时:
装饰器的__call__方法接收的是整个类对象,我们给这个类添加了method属性——相当于给类绑定了一个方法。之后所有TestClassWrapped的实例,都会继承这个类方法,这个method是类的成员,所有实例共享。当直接调用
Deco('deco')(test)时:
这里test是TestClass的单个实例对象,装饰器的__call__方法接收的是这个实例。我们给这个特定实例单独添加了method属性,它只是这个实例独有的普通函数,和类本身没有关联——其他TestClass实例不会拥有这个method。
问题2:为何test.method和test_wrapped.method返回结果不同?看起来test_wrapped.method的第一个参数是self,而test.method的第一个参数却不是,两者为何存在这种差异?
这是因为函数的绑定方式完全不一样:
对于
test_wrapped.method:
它是绑定在TestClassWrapped类上的方法,当实例调用它时,Python会自动触发「方法绑定机制」——把实例本身作为第一个参数(也就是我们常说的self)传入函数。你的inner_func接收一个参数whatisit,这个参数在这里被自动填充为test_wrapped实例本身,所以test_wrapped.method()返回的就是实例自己,自然和test_wrapped相等。对于
test.method:
它是直接赋值给test实例的普通函数,没有经过类的方法绑定流程。Python不会自动给它传入self,所以调用时必须手动传一个参数(比如你传的'whatisit'),函数才会返回这个参数。如果像test_wrapped那样不带参数调用test.method(),会直接报错,因为函数需要一个参数但没收到。
内容的提问来源于stack exchange,提问作者watseob

