Python 如何在没有大量手动编辑的情况下,将一个类替换为大量文件中另一个模块中的另一个类?

Python 如何在没有大量手动编辑的情况下,将一个类替换为大量文件中另一个模块中的另一个类?,python,automation,sed,rope,Python,Automation,Sed,Rope,基本上,我有很多Python类(代表我们的数据库模式),看起来像这样: from foo import xyz, b, c class bar(object): x = xyz() y = b() z = c() …我想把它改成: from foo import b, c from baz import foobar class bar(object): x = foobar() y = b() z = c() 本质上,我只想用foobar

基本上,我有很多Python类(代表我们的数据库模式),看起来像这样:

from foo import xyz, b, c

class bar(object):
    x = xyz()
    y = b()
    z = c()
…我想把它改成:

from foo import b, c
from baz import foobar

class bar(object):
    x = foobar()
    y = b()
    z = c()
本质上,我只想用
foobar
替换
xyz
的所有实例。我可以接受将a的进口留在,因此这也可以:

from foo import a, b, c
from baz import foobar

class bar(object):
    x = foobar()
    y = b()
    z = c()
在这个问题上执行
sed s/xyz/foobar/
似乎很简单,但是我仍然必须返回并更改导入语句。我可以做一些手工工作,但我想学习新的方法来减少工作量


那么,你将如何做这种改变?我能和塞德一起做些什么吗?或者绳子(我看不到任何明显的对我有帮助的东西)?

sed s/a/m将是灾难性的,因为酒吧将改为bmr

如果变量名非常短和/或非唯一、不可正则, 那么也许最简单的方法就是插入

from baz import m as a
这样,您就不必再进一步修改文件中的任何其他代码

你可以用sed来改变

from foo import a,b,c 

虽然

from foo import a,b,c 
from baz import m as a

也可以,因为上次导入成功。

我没有使用rope,但您不能将a移到baz,然后将baz.a重命名为baz.m。您可以在其他语言的重构工具中使用,并且建议可以


对于最小的编辑—但可能更糟糕的样式和可维护性—请使用foo。调用baz.m

Monkey补丁将是一种快速而肮脏的方法—在执行任何其他导入之前,请执行以下初步操作:

import foo
import baz
foo.a = baz.m

现在,模块
foo
的属性
a
的每次后续使用实际上都将根据需要使用模块
baz
的类
m
,而不是模块
foo
的原始类
a
。不是特别干净,但可能相当有效。只需确保在任何其他导入之前进行monkey修补(您也可以在对象图中查找在修补之前放置的对
foo.a
的每个引用,并将其更改为
baz.m
,但这更重、更复杂)。

您可以尝试此
sed
脚本:

sed -r 's/(^from foo import.*)(xyz, |, xyz)(.*)/\1\3/; T; a\from baz import foobar'
或者,相当于:

sed 's/\(^from foo import.*\)\(xyz, \|, xyz\)\(.*\)/\1\3/; T; a\from baz import foobar'
如果您这样尝试,您将得到如下结果:

$ echo "from foo import xyz, b, c"|sed -r 's/(^from foo import.*)(xyz, |, xyz)(.*)/\1\3/; T; a\from baz import foobar'
from foo import b, c
from baz import foobar

$ echo "from foo import b, xyz, c"|sed -r 's/(^from foo import.*)(xyz, |, xyz)(.*)/\1\3/; T; a\from baz import foobar'
from foo import b, c
from baz import foobar

$ echo "from foo import b, c, xyz"|sed -r 's/(^from foo import.*)(xyz, |, xyz)(.*)/\1\3/; T; a\from baz import foobar'
from foo import b, c
from baz import foobar
如果未进行替换,
sed
中的
T
命令将分支到标签(如果未给出标签,则分支到末尾)。在本例中,“from baz”行仅追加一次:

$ echo "from foo import d, e, f
from foo import xyz, b, c
from bar import g, h, i"|sed -r 's/(^from foo import.*)(xyz, |, xyz)(.*)/\1\3/;a\from baz import foobar'
from foo import d, e, f
from foo import b, c
from baz import foobar
from bar import g, h, i

我不会使用monkeypatching,我会实现自己的功能:

import foo

def xyz():
    return foo.xyz()

def b():
    return foo.b()

def c():
    return foo.c()
现在我可以更改
xyz()
,让它做我想做的任何事情,如果我想显式调用
foo.xyz()
,我可以


此外,如果我将该代码粘贴到一个模块中,我可以在当前使用
foo

的所有模块中用
从foo import
全局替换
。为了简单起见,我只是使用了
m
a
。我更新了页面,使其更清晰(尽管有点俗气)。sed方法不起作用,因为我可能还会遇到类似foo import b、c、xyz的
。实际上,baz代表我自己的库,foo代表第三方库。在它们之间来回移动东西是不可行的。你仍然可以进行移动-你的代码将被编辑并在调用它的代码中使用baz.a,但返回到未更改的foo,并按照Alex Martelli建议的猴子补丁在baz中实现a。不幸的是,我仍然需要在几个地方使用a。我有点犹豫要不要做更多的诡计来绕过这个问题,因为foo是一个第三方图书馆。@Jason,啊,好吧——也许你可以在需要它的地方“反转monkeypatch”foo的原始a(你可以在重新分配它之前把它藏起来)?否则,通过修改代码当然可以做到这一点,但要复杂得多(除非名称是无误的,正如您在编辑xyz而不是;-)时所指出的那样)。
import foo

def xyz():
    return foo.xyz()

def b():
    return foo.b()

def c():
    return foo.c()