Горячий обмен кода Python (функции типа утки?) - PullRequest
4 голосов
/ 08 августа 2010

Я слишком долго думал об этом и не догадывался, может быть, некоторые из вас могут помочь.

У меня есть папка скриптов 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 в папке может быть просто средней частью кода. Однако обычный модуль не будет работать здесь (если я не ошибаюсь), потому что я получу код, который мне нужно выполнить, из аргумента, который будет строкой, и, таким образом, я не буду знать, какую функцию запустить до времени выполнения .

Итак, я придумал еще два решения:

  1. Я мог бы написать несколько операторов if, по одному для запуска каждого сценария на основе определенного параметра. Я отклонил это, поскольку это даже хуже, чем предыдущий дизайн.
  2. Я мог бы использовать:

    os.command (sys.argv [0] scriptName.py)

    который будет запускать скрипт, но вызов python для вызова python не кажется мне очень элегантным.

Так у кого-нибудь есть другие идеи? Спасибо.

Ответы [ 6 ]

4 голосов
/ 08 августа 2010

Другое возможное решение состоит в том, чтобы каждый из ваших повторяющихся файлов импортировал функции из основного файла

from topAndBottom import top, bottom
top()
# do middle stuff
bottom()
4 голосов
/ 08 августа 2010

Если вы знаете имя функции в виде строки и имя модуля в виде строки, то вы можете сделать

mod = __import__(module_name)
fn = getattr(mod, fn_name)
fn()
2 голосов
/ 08 августа 2010

В дополнение к нескольким уже опубликованным ответам рассмотрим Шаблонный метод шаблон проектирования: создайте абстрактный класс, такой как

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) для случаев, когда количество или сложность «подключаемых элементов» продолжает расти - Шаблонный метод (несмотря на его ужасное название ;-) - это надежный, хорошо себя зарекомендовавший и масштабируемый шаблон [[иногда слишком жестко, но это именно то, о чем я говорю в этих многочисленных технических выступлениях - и эта проблема не относится к этому конкретному случаю использования]].

0 голосов
/ 08 августа 2010

Как насчет этого?

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
0 голосов
/ 08 августа 2010

Импорт модуля (как объяснено в других ответах), безусловно, является более чистым способом сделать это, но если по какой-то причине это не работает, если вы не делаете ничего странного, вы можете использовать exec.Он в основном запускает содержимое другого файла, как если бы он был включен в текущий файл в точке, где вызывается exec.Это самая близкая вещь, которую Python имеет к source выражению, включенному во многие оболочки.Как минимум, что-то вроде этого должно работать:

exec(open(filename).read(None))
0 голосов
/ 08 августа 2010

Однако обычный модуль здесь не будет работать (если я не ошибаюсь), потому что я получу код, который мне нужно выполнить, из аргумента, который будет строкой, и, таким образом, я не буду знать, какую функцию работать до времени выполнения.

Это будет работать просто отлично - используйте встроенный __import__ или, если у вас очень сложный макет, модуль imp для импорта вашего скрипта. И тогда вы можете получить функцию, например, module.__dict__[funcname].

...