Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Python中修改def的行为?_Python_Metaprogramming - Fatal编程技术网

如何在Python中修改def的行为?

如何在Python中修改def的行为?,python,metaprogramming,Python,Metaprogramming,Python中的大多数内容都是可以随时修改的,甚至可以使用您最喜欢的代码对象直接使用Types.FunctionType实例化函数。这并不是说你必须这样做,但作为一次学习经验,我正在试图弄清楚如何在Python本身的中修改def的行为(修改语言定义感觉像是作弊) 对于类,这可以在3.1+中通过\uuuu build\uu class\uuu钩子轻松完成是否有类似的机械连接功能建筑? 到目前为止,我已经尝试过修改compile(),eval(),exec(),type(),Types.Functi

Python中的大多数内容都是可以随时修改的,甚至可以使用您最喜欢的代码对象直接使用Types.FunctionType实例化函数。这并不是说你必须这样做,但作为一次学习经验,我正在试图弄清楚如何在Python本身的中修改
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)