Python 如何在不修改AST的情况下动态更改函数的签名?

Python 如何在不修改AST的情况下动态更改函数的签名?,python,Python,我正在编写一个与Python的@dataclass等效的代码,并试图对修饰类的构造函数进行monkeypatch。我的装饰师目前如下所示: def装饰器(装饰类): 定义初始(自我,**kwargs): #做事 装饰类。装饰初始化__ 返校班 我希望能够根据类属性动态设置新创建的\uuuu init\uuu方法的参数。例如,假设我们有一个classPerson: @decorator 班长: 姓名:str 年龄:整数 我期望的行为是动态生成以下构造函数,并像我目前在decorator中所做的

我正在编写一个与Python的
@dataclass
等效的代码,并试图对修饰类的构造函数进行monkeypatch。我的装饰师目前如下所示:

def装饰器(装饰类):
定义初始(自我,**kwargs):
#做事
装饰类。装饰初始化__
返校班
我希望能够根据类属性动态设置新创建的
\uuuu init\uuu
方法的参数。例如,假设我们有一个class
Person

@decorator
班长:
姓名:str
年龄:整数
我期望的行为是动态生成以下构造函数,并像我目前在decorator中所做的那样对其进行修补

def\uuuuu init\uuuuuuu(自我、姓名、年龄):
self.name=名称
self.age=年龄
这种行为可能是通过在运行时使用AST实现的,但它显然是以性能为代价的,这是我希望避免的。有没有(例如)直接与
函数
对象交互的方法


注意:提供的解决方案描述不好,无法运行。

您可以使用
setattr
*args/**kwargs
来执行此操作,而不会弄乱AST。根据您的解释,我假设您不关心原始的
\uuuu init\uuu
函数

下面的代码生成了一个为类成员量身定制的
\uuuuu init\uuuu
函数:

def装饰器(cls): #找出属性。标准类属性的优先级高于注释 attributes=[cls中名称的名称。\如果不是name.startswith(“”“”)] 如果cls中的“\uuuuu注释”\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu 对于cls中的属性名称,请参见注释: 如果属性中没有属性名称: attributes.append(属性名称) 定义初始化(self,*args,**kwargs): 对于attr_name,zip中的值(属性、参数): setattr(自身、属性名称、值) 对于暂定名称,以kwargs.items()为单位的值: 如果在属性中使用名称: setattr(自身、暂定名称、值) cls.\uuuuu init\uuuuuu=\uuuuuuu init__ 返回cls 它基本上是在
\uuuuu dict\uuuuu
\uuuuuuu注释\uuuuuuuuu
中搜索不以
\uuuu
开头的条目,并允许将它们传递给构造函数。我排除了以单个
开头的条目,因为它们通常不会从构造函数中设置。以下是一些测试:

@decorator
班长:
姓名:str
年龄:整数
约翰=人(“约翰”,32岁)
assert john.name==“john”
断言john.age==32
玛丽=人(姓名=玛丽,年龄=18岁)
assert mary.name=='mary'
年龄=18岁
这也适用于具有默认属性的类:

@decorator
类别其他人:
name='johndoe'
年龄=21
穆斯塔法=其他人(“穆斯塔法”,15)
assert mustafa.name==“mustafa”
断言mustafa.age==15
yuko=其他人(姓名='yuko',年龄=71岁)
断言yuko.name==“yuko”
断言yuko.age==71

我认为可以包装原始的
\uuuu init\uuuu
,但我不相信对原始参数可以做任何非常明智的事情。

数据类本身只使用
exec
。@user2357112supportsMonica这很简单,这种方法不存在安全问题吗?您必须非常小心如何操作。一个特别值得关注的问题是,如果有人在动态生成的类上调用您的decorator,该类的
\uuuuu dict\uuuu
\uuuuu注释中可能有条目,而这些条目不是合法的Python标识符,那么会发生什么情况。事实上,我并不关心原始的
\uuuu init\uuu
。你的解决方案是一个绝妙的解决方案,我甚至没有想到。非常感谢。