如何通过'替换现有的(或以其他方式扩展)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'