首页 新闻 会员 周边 捐助

装饰类未调用原类中的方法

0
[已解决问题] 解决于 2025-08-02 16:25

def inner(cls):
class wrapper():
def init(self,args,**kargs):
self.warp = cls(
args,**kargs)
return wrapper
class stu():
def init(self,name,age):
self.name = name
self.age = age
def get(self):
print(self.name,self.age)

if name == "main":
stu = inner(stu)
stu = stu("xiaming",12)
stu.get()

我本想通过装饰器来装饰类,但是报:
stu.get()
^^^^^^^
AttributeError: 'wrapper' object has no attribute 'get'
这是什么原因,我需要怎么改

_java_python的主页 _java_python | 小虾三级 | 园豆:738
提问于:2025-08-02 14:57
< >
分享
最佳答案
0

我们调用stu.get(),但是wrapper的实例并没有get方法,因为wrapper类只定义了__init__方法,所以会报错:'wrapper' object has no attribute 'get'
我们想要的效果是,装饰后的类在调用方法时能够像原类一样工作。这里装饰器返回的是一个新的类wrapper,而原类的方法并没有被代理

我们可以让wrapper类代理所有对原类实例的属性和方法访问。这可以通过在wrapper类中实现__getattr__方法来实现。这样,当访问wrapper实例上不存在的属性或方法时,会尝试访问其内部包裹的self.warp(即原类的实例)的相应属性或方法。
修改后的代码:
wrapper类中添加:
def getattr(self, name):
return getattr(self.warp, name)
这样,当我们调用stu.get()时,由于wrapper实例本身没有get方法,就会调用__getattr__,然后去self.warp(即原stu类的实例)上找get方法并调用。

def inner(cls):
class wrapper:
def init(self, args, **kargs):
self.wrapped = cls(
args, **kargs) # 存储原始类的实例

    # 代理所有未定义的方法到原始类的实例
    def __getattr__(self, name):
        return getattr(self.wrapped, name)
return wrapper

class stu:
def init(self, name, age):
self.name = name
self.age = age
def get(self):
print(self.name, self.age)

if name == "main":
stu = inner(stu) # 装饰原始类
s = stu("xiaming", 12) # 创建装饰后的实例
s.get() # 正确调用:输出 xiaming 12

注意:通过__getattr__只能转发实例属性和方法,对于类属性(比如在类上直接调用的)或者特殊方法(如__str__等)可能不会按预期工作。因为__getattr__只在查找实例属性时被调用,而不会在查找类属性时被调用。另外,一些特殊方法(如__len____str__等)通常是在类上查找,而不是在实例上查找,所以不会经过__getattr__。因此,如果需要这些特殊方法,可能需要单独在wrapper类中实现,或者使用其他方法(如继承)。
不过,对于普通方法,这样是可行的。

其他实现方式(可选):
方法二:使用继承(更简洁)

python
def inner(cls):
class wrapper(cls): # 直接继承原始类
def init(self, args, **kargs):
super().init(
args, **kargs)
return wrapper
优点:自动继承所有方法,无需手动代理。

缺点:可能意外覆盖父类行为。

_java_python | 小虾三级 |园豆:738 | 2025-08-02 15:06

getattr 方法的作用

python
def getattr(self, name):
return getattr(self.warp, name)
这是 Python 的特殊方法

当访问对象上不存在的属性/方法时自动调用

name 参数是要访问的属性/方法名

getattr() 函数的作用

python
getattr(self.warp, name)
内置函数,等价于 self.warp.name

动态获取对象属性/方法

如果 name 是方法,返回的是绑定方法(bound method)
为什么这个代理有效
当您调用 stu.get() 时(这里的 stu 是 wrapper 实例):

Python 首先在 wrapper 实例上查找 get 方法

因为 wrapper 类没有定义 get 方法,触发 getattr

getattr 执行:getattr(self.warp, "get")

这会:

在 self.warp(原始 stu 类的实例)上查找 get 方法

找到后返回这个绑定方法(已经绑定了 self.warp 实例)

返回的方法被调用:get() → 实际执行 self.warp.get()
这种代理方式本质上是将调用转发给内部包含的原始类实例
这种模式在 Python 中很常见,称为:

代理模式 (Proxy Pattern)

装饰器模式 (Decorator Pattern)

适配器模式 (Adapter Pattern)
getattr函数:它是Python内置函数,用于获取对象的属性。它的作用等同于点号(.)访问,但可以动态指定属性名。例如:
getattr(obj, 'name') # 相当于 obj.name
getattr(obj, 'method') # 相当于 obj.method
因此,__getattr__方法中的return getattr(self.warp, name)的意思就是:返回self.warp对象的名为name的属性。

_java_python | 园豆:738 (小虾三级) | 2025-08-03 15:16

def inner(cls):
class wrapper():
def init(self,args,**kargs):
self.warp = cls(
args,**kargs)
def getattr(self,name):
return getattr(self.warp,name)
return wrapper
@inner
class stu():
def init(self,name,age):
self.name = name
self.age = age
def get(self):
print(self.name,self.age)

if name == "main":
stu = stu("xiaming",12)
stu.get()

_java_python | 园豆:738 (小虾三级) | 2025-08-03 15:17
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册