Горячая замена Python Code (функции типа утки?)
-
26-09-2019 - |
Вопрос
Я думал об этом слишком долго и не получил никакой идеи, может быть, некоторые из вас могут помочь.
У меня есть папка сценариев Python, все из которых имеют одинаковое окружающее тело (буквально, я создал его из скрипта оболочки), но иметь один кусок, который отличается от всех них. Другими словами:
Top piece of code (always the same)
Middle piece of code (changes from file to file)
Bottom piece of code (always the same)
И я понял сегодня, что это плохое представление, например, если я хочу изменить что-то из верхних или нижних сечений, мне нужно написать сценарий оболочки, чтобы сделать это. (Не то, что это сложно, просто похоже, что это очень плохой код).
Так что я хочу сделать, есть один внешний скрипт Python, который похож на это:
Top piece of code
Dynamic function that calls the middle piece of code (based on a parameter)
Bottom piece of code
И тогда каждый другой файл Python в папке может быть просто средний кусок кода. Тем не менее, обычный модуль не будет работать здесь (если я не ошибаюсь), потому что я получил бы код, который мне нужно выполнить из аргумента, который был бы строкой, и, таким образом, я бы не знал, какую функцию выполнять до выполнения времени Отказ
Поэтому я придумал еще два решения:
- Я мог бы записать кучу заявлений, чтобы запустить каждый сценарий на основе определенного параметра. Я отклонил это, так как даже хуже, чем предыдущий дизайн.
Я мог бы использовать:
os.command (sys.argv [0] scriptname.py)
Что будет запускать скрипт, но призывая питона называть Python, не кажется мне очень элегантным для меня.
Так у кого-нибудь есть какие-то другие идеи? Спасибо.
Решение
Если вы знаете имя функции как строку и имя модуля как строку, то вы можете сделать
mod = __import__(module_name)
fn = getattr(mod, fn_name)
fn()
Другие советы
Другое возможное решение состоит в том, чтобы каждый из ваших повторяющихся файлов импортирует функциональные возможности из основного файла
from topAndBottom import top, bottom
top()
# do middle stuff
bottom()
В дополнение к нескольким ответам уже опубликовано, рассмотрите Метод шаблона Шаблон дизайна: сделать абстрактный класс, такой как
class Base(object):
def top(self): ...
def bottom(self): ...
def middle(self): raise NotImplementedError
def doit(self):
self.top()
self.middle()
self.bottom()
Каждый модуль подключаемых, затем делает класс, который наследует из этого Base
и должен переопределить middle
с соответствующим кодом.
Возможно, не гарантировано для этого простого случая (вам все еще нужно импортировать правильный модуль, чтобы создать свой класс и вызов doit
На нем), но все еще стоит иметь в виду (вместе со своими многочисленными вариациями Pythonic, которые я наглядно объяснил во многих технологических переговорах, теперь доступных на YouTube) для случаев, когда число или сложность «плюшек штук» продолжает расти - метод шаблона (Несмотря на свое ужасное имя ;-) - это сплошной, хорошо доказанный и высокомасштабный шаблон [[иногда слишком жесткий, но это именно то, что я обращаюсь в тех много технических переговоров - и эта проблема не применяется к этому конкретному Используйте Case]].
Тем не менее, обычный модуль не будет работать здесь (если я не ошибаюсь), потому что я получил бы код, который мне нужно выполнить из аргумента, который был бы строкой, и, таким образом, я бы не знал, какую функцию выполнять до выполнения времени Отказ
Это будет работать просто хорошо - использовать __import__
встроенный или, если у вас очень сложный макет, укреплять Модуль для импорта вашего сценария. И тогда вы можете получить функцию module.__dict__[funcname]
Например.
Импорт модуля (как объяснено в других ответах), безусловно, является более чистым способом для этого, но если по какой-то причине это не работает, пока вы не делаете ничего странного, вы можете использовать exec
. Отказ Он в основном запускает содержимое другого файла, как если бы он был включен в текущий файл в точке, где exec
называется. Это самое близкое, что Python имеет к source
Заявление о виду включено во многие снаряды. Как минимум, что-то вроде этого должно работать:
exec(open(filename).read(None))
Как насчет этого?
function do_thing_one():
pass
function do_thing_two():
pass
dispatch = { "one" : do_thing_one,
"two" : do_thing_two,
}
# do something to get your string from the command line (optparse, argv, whatever)
# and put it in variable "mystring"
# do top thing
f = dispatch[mystring]
f()
# do bottom thing