如何通过'替换现有的(或以其他方式扩展)reposurger的Python类方法;执行官';和';评估';?
(在撰写本文时)关于这个话题的文章很少。如果宏(如何通过'替换现有的(或以其他方式扩展)reposurger的Python类方法;执行官';和';评估';?,python,reposurgeon,Python,Reposurgeon,(在撰写本文时)关于这个话题的文章很少。如果宏(define)的使用不足以满足我的需要,我如何扩展功能 它给出的唯一线索是: 代码可以完全访问所有内部数据结构。定义的函数可供以后的eval调用访问 但这到底意味着什么呢 我们还了解到: 通常,这是对前一个exec定义的函数的调用。变量_repository和_selection将具有明显的值。注意_选择将是一个整数列表,而不是对象列表 初步说明 我将使用斜体内联代码(如此)表示Python代码,使用“普通”内联代码(如此)表示命令。对于代码块,介
define
)的使用不足以满足我的需要,我如何扩展功能
它给出的唯一线索是:
代码可以完全访问所有内部数据结构。定义的函数可供以后的eval调用访问
但这到底意味着什么呢
我们还了解到:
通常,这是对前一个exec定义的函数的调用。变量_repository和_selection将具有明显的值。注意_选择将是一个整数列表,而不是对象列表
初步说明
我将使用斜体内联代码(如此
)表示Python代码,使用“普通”内联代码(如此
)表示命令。对于代码块,介绍性描述应该提供上下文,即它是命令还是Python代码
本文讨论了Repo外科医生的3.10版,这是本文撰写时的最新版本
简介
是用Python编写的,并显式允许execfile()
其中的其他Python代码。该命令的命令语法为:
exec </path/to/python-source.py
并在提示下发出以下命令:
exec </path/to/your/python-code.py
exec </path/to/your/python-code.py
这将产生预期输出:
Hello world!
不过,您可能希望使用与我不同的选项。任何适合你需要的
注意:在任何情况下,即使是空的选择也会导致调用Python代码!例如,我加载的回购中的选择=I
为空,但我仍将看到上面生成的输出。为调用代码提供任何选择都很重要
探索Python代码运行的上下文
通过上面这个简单的例子,我们可以检查它是否有效。现在,我们来探索除了文档中提到的\u选择
和\u存储库
之外,我们还可以访问哪些内容
将函数myfunc
更改为:
应该让我们感觉到我们在处理什么
更改(并保存)后,只需重新运行:
您应该看到globals()
和locals()
的内容转储
您会注意到,即使在eval
的上下文中,您仍然可以访问self
(在本例中是globals()
的一部分)。这很有用
正如我前面提到的,您还可以修改运行代码的\uuuu main\uuuuu.reposurger
的实例(下面将详细介绍这一点)
要查看所有方法等,请在函数中使用dir(self)
(或者在exec
-ing Python代码文件时在顶层使用)
因此,只需将这一行添加到myfunc
:
使之成为:
def myfunc():
from pprint import pprint
pprint(globals())
pprint(locals())
dir(self)
再次调用exec
和eval
命令后(在Linux上,就像在shell中使用cursor Up一样调用它),现在应该可以看到列出的大多数函数,您还可以找到代码
注意:只需重新运行Repo外科医生的exec
命令,然后再运行另一个eval myfunc()
即可添加\uuuu main\uuuuu.repo外科医生的属性输出
虽然到目前为止,所有这些都很酷,应该让您了解如何在Repo外科医生中运行自己的Python代码,但您也可以替换现有的方法。继续读下去
连接到系统并替换功能
通过访问self
可以添加功能和修改现有功能
reposurgical.precmd
似乎是这方面的合适人选。它是在运行实际命令之前被调用的方法,执行语法检查以及设置选择集,这在许多命令中非常重要
我们需要的是precmd
的原型。这是:
def precmd(self, line):
替换方法的诀窍又是什么?领路人
我们可以简单地将其用作exec
的(完整)Python文件:
if self:
if not 'orig_precmd' in self.__dict__:
setattr(self, 'orig_precmd', self.precmd) # save original precmd
def myprecmd(self, line):
print("[pre-precmd] '%s'" % line)
orig_precmd = getattr(self, 'orig_precmd')
return self.orig_precmd(line)
setattr(self, 'precmd', myprecmd.__get__(self, self.__class__))
if self:
仅用于确定代码的范围
- 对“orig_precmd”的检查可确保在后续调用
exec
时不会再次覆盖此属性的值
myprecmd(self,line):
包含我们版本的\uuu main\uuuu.reposurgical.precmd
。它增加了一个很棒的新功能,可以模仿输入的命令
- 最后但并非最不重要的一点是,第二个
setattr()
简单地用我们的版本覆盖了\u main\u.reposurgical.precmd
。任何后续调用self.precmd()
都将通过我们的“钩子”
请记住,我们正在重写内部代码,所以请小心行事,不要做任何愚蠢的事情。代码可读性很强,尽管代码的位置高达10k
下次您发出任何命令时,应该让它向您重复。考虑以下内容(Realurgon提示符加上输出摘录):
=O list
是我输入的命令,[pre-precmd]'=O list'
是它产生的输出(后面是实际输出,因为我在我的版本中调用了\uu main\uuuuu.reposurgical.precmd
的原始实现)
结论
reposurgical命令exec
和eval
提供了一种强大的方法来覆盖现有功能并在reposurgical中添加新功能
钩子示例是一个“简单”扩展函数的超集,它使用eval
和以前的exec
'd函数。它允许将代码潜入我们的内心,并将其屈服于我们的意志,不管它有什么缺点(到目前为止,我只发现了少数缺点)
库
=O eval myfunc()
dir(self)
def myfunc():
from pprint import pprint
pprint(globals())
pprint(locals())
dir(self)
def precmd(self, line):
if self:
if not 'orig_precmd' in self.__dict__:
setattr(self, 'orig_precmd', self.precmd) # save original precmd
def myprecmd(self, line):
print("[pre-precmd] '%s'" % line)
orig_precmd = getattr(self, 'orig_precmd')
return self.orig_precmd(line)
setattr(self, 'precmd', myprecmd.__get__(self, self.__class__))
reposurgeon% =O list
[pre-precmd] '=O list'