如何在Python中修改def的行为?
Python中的大多数内容都是可以随时修改的,甚至可以使用您最喜欢的代码对象直接使用Types.FunctionType实例化函数。这并不是说你必须这样做,但作为一次学习经验,我正在试图弄清楚如何在Python本身的中修改如何在Python中修改def的行为?,python,metaprogramming,Python,Metaprogramming,Python中的大多数内容都是可以随时修改的,甚至可以使用您最喜欢的代码对象直接使用Types.FunctionType实例化函数。这并不是说你必须这样做,但作为一次学习经验,我正在试图弄清楚如何在Python本身的中修改def的行为(修改语言定义感觉像是作弊) 对于类,这可以在3.1+中通过\uuuu build\uu class\uuu钩子轻松完成是否有类似的机械连接功能建筑? 到目前为止,我已经尝试过修改compile(),eval(),exec(),type(),Types.Functi
def
的行为(修改语言定义感觉像是作弊)
对于类,这可以在3.1+中通过\uuuu build\uu class\uuu
钩子轻松完成是否有类似的机械连接功能建筑?
到目前为止,我已经尝试过修改
compile()
,eval()
,exec()
,type()
,Types.FunctionType
,以及任何我能在任何地方找到的相关内容。据我所知,def
在创建函数对象并将其加载到globals()
中时,不会执行这些操作。尽可能详细地说,当我们定义一个函数时,到底会发生什么?整个过程是在底层C代码的幕后完成的吗?这里有龙。继续下去,后果自负。
由于我一直无法找到我想要的功能的文档,而且绝大多数人都没有回应,所以我要冒险说它根本不存在。也就是说,您可以修补类定义,使其行为类似于函数定义。很有趣,对吧
在Python3.1+中,以下代码(附带一个助手文件,我将在一分钟内介绍)是行为与预期大致相同的法律代码
fib类(n=5):
如果n<2:
res=1
a=b=1
对于范围(2,n+1)内的i:
a、 b=b,a+b
res=b
现在检查代码的输出:
>>> fib(n=3)
3
>>> fib(n=4)
5
>>> fib()
8
>>> fib(n=10)
89
我们可以像调用带有默认参数的函数一样调用这个类,并获得正确的值。请注意,完全缺少\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
警告:这可能对您来说并不意外,但以下内容肯定还没有准备好生产(对不起,我还在学习)
我们选择的武器是为了我们自己的利益和利益而超越内置的。请注意,python应用程序中只有一个内置文件的副本,将其混入一个模块会影响所有模块。为了减轻伤害,我们将把所有巫毒移到它自己的模块中,为了简单起见,我刚才称之为base
我选择这样做的方式是允许每个模块向base
注册自己,以及它们希望应用于类函数的装饰器(如果你没有对所有类都做些什么,为什么要费劲修改每个类?)
导入内置项
_覆盖={}
def寄存器(f,模块=无):
模块=如果模块不是其他f.\U模块,则为模块__
_覆盖[模块]=f
def撤销(x):
尝试:
del_覆盖[x]
除KeyError外:
删除覆盖[x.\U模块\U]
这看起来像是很多代码,但它所做的只是制作一个字典\u覆盖
,并允许来自任何模块的代码在该字典中注册自己。如果他们想使用外部函数,但仍然有奇怪的类行为只适用于他们自己,我们允许模块显式地将自己传递到register()
函数中
在开始处理任何事情之前,我们需要存储旧的\uuu build\u class\uuu()
函数,以便在任何未注册的模块中使用它
_obc = builtins.__build_class__
新的\uuuuu build\u class()
函数只检查模块是否已注册。如果是这样的话,它会产生一些魔力,否则它会调用原始的内置函数
def_bc(f,name,*a,mc=None,**k):
mc=如果mc不是其他mc,则键入
尝试:
w=_覆盖[f._模块__]
除KeyError外:
return _obc(f,name,*a,元类=mc,**k)
返回_cbc(f,name,w,*a,**k)
请注意,类的默认类型是type
。此外,我们还显式地将包装器w
从\u overrides
传递到我们的自定义方法\u cbc()
,因为我们无法控制revoke()
。如果我们只是检查模块是否已注册,用户很可能会在查询包装器的\u覆盖
之前注销它
就像对待代码一样对待类的魔力而言,它是\uuuu build\uu code\uuuu()
的替代品
在这里,函数\u cbc()
在读取我们的类定义时,获取Python解释器返回的函数对象f
,并将其代码直接传递到exec()
。如果您碰巧将任何关键字参数传递给函数g()
,它也会很高兴地将这些参数扔到exec()
中。当所有这些都完成后,您的类函数应该已经为res
分配了一个值,所以我们返回该值
但是我们仍然需要创建一个类。type
元类是创建普通类的标准方法,因此我们创建了一个。要真正调用我们刚刚创建的g()
东西,我们将它分配给新类上的\uuuuuuuuuuuuuuuuuu()
,这样当有人试图实例化我们的类时,所有内容都会传递到\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu()
(以及一个我们不关心的额外的
最后,我们使用自定义方法覆盖内置项
builtins.__build_class__ = _bc
要使用这些新玩具,我们需要进口。我调用了我的库base
,但您几乎可以使用任何东西
import base
然后base.register()
是开始更改类定义工作方式的钩子。我们的延迟实现需要传入一个函数,因此我们可以只使用标识
base.register(lambda f: f)
在这一点上,斐波那契公司
base.register(lambda f: f)