Как я могу заменить класс другим классом из другого модуля во многих файлах без большого количества ручного редактирования?
По сути, у меня есть много классов 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()
По сути, я просто хочу заменить все экземпляры xyz
с foobar
, Для меня приемлемо оставить импорт в, так что это также будет хорошо:
from foo import a, b, c
from baz import foobar
class bar(object):
x = foobar()
y = b()
z = c()
Это кажется тривиальным sed s/xyz/foobar/
на этом, но тогда мне все равно придется вернуться и изменить операторы импорта. Я хорошо справляюсь с какой-то ручной работой, но я хотел бы изучить новые способы минимизировать ее количество.
Так как бы вы сделали это изменение? Могу ли я что-нибудь сделать с sed для этого? Или веревка (я не вижу ничего очевидного, что могло бы мне здесь помочь)?
5 ответов
Обезьяны-патчи были бы быстрым и грязным способом сделать это - прежде чем выполнять какой-либо другой импорт, выполните следующие предварительные действия:
import foo
import baz
foo.a = baz.m
теперь, каждое последующее использование атрибута a
модуля foo
на самом деле будет использовать класс m
модуля baz
, как требуется, а не оригинальный класс a
модуля foo
, Не особо чистый, но потенциально довольно эффективный. Просто сделайте так, чтобы патч происходил перед любым другим импортом (вы также можете бегать по всему графу объектов, чтобы найти каждую ссылку на foo.a
который был установлен на месте до исправления и изменить его на baz.m
, но это намного тяжелее и сложнее).
SED S / A / M будет катастрофическим, так как бар будет изменен на Bmr.
Если имена переменных действительно короткие и / или неуникальные, не поддерживают регулярные выражения, то, возможно, проще всего было бы вставить
from baz import m as a
Тогда вам не нужно изменять какой-либо другой код ниже в файле.
Вы можете использовать sed, чтобы изменить
from foo import a,b,c
в
from foo import b,c
хоть
from foo import a,b,c
from baz import m as a
будет работать, так как последний импорт выигрывает.
Вы можете попробовать это 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
T
команда в sed
переходят к метке (или к концу, если метка не указана), если не производится подстановка. В этом примере строка "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
Я не использовал веревку, но вы не можете переместить a в baz, а затем переименовать baz.a в baz.m Вы можете использовать другие инструменты рефакторинга для других языков, и страница веревки подсказывает, что это возможно.
Для минимального редактирования - но, вероятно, худшего стиля и удобства сопровождения, сделайте foo.a вызовом baz.m
Я бы не использовал monkeypatching, я бы реализовал свои собственные функции:
import foo
def xyz():
return foo.xyz()
def b():
return foo.b()
def c():
return foo.c()
Теперь я могу изменить xyz()
заставить его делать все, что я хочу, и если я когда-либо захочу явно foo.xyz()
, Я могу.
Кроме того, если я вставлю этот код в модуль, я могу глобально заменить from foo import
с from my_foo import
во всех модулях, которые в настоящее время используют foo
,