Условное определение функции в модуле - программирование
Подтвердить что ты не робот

Условное определение функции в модуле

Мой вопрос - найти "хороший способ" определения функции, реализация которой отличается в соответствии с заданным критерием. Эта функция будет вызываться из нескольких сценариев, поэтому я должен поместить ее в модуль.

Для примера, мой критерий касается той платформы, на которой запущен script, но ясно, что тест может ни на что повлиять. Мои функции позволяют постоянно определять/извлекать переменные среды, поэтому я создал модуль с именем persistenv.py в соответствии со следующей схемой (РЕШЕНИЕ 1):

# CROSS-PLATFORM PART
def my_function1() :
    # ... body1 ...

# WINDOWS-ONLY PART
if sys.platform.lower().startswith('win') :
    def my_function2() :
        # ...body2 for Windows...

# LINUX-ONLY PART
elif sys.platform.lower().startswith('linux') :
    def my_function2() :
        # ...body2 for Linux...

else :
    raise ImportError('Your platform is not supported')

Вышеприведенное введение двух возможных определений одной и той же функции в одном модуле. Во всяком случае, это звучало для меня гораздо чище, чем тестирование платформы при каждом вызове функции (РЕШЕНИЕ 2):

# CROSS-PLATFORM PART
def my_function1() :
    # ... body1 ...


def my_function2() :

    # WINDOWS-ONLY PART
    if sys.platform.lower().startswith('win') :
        # ...body2 for Windows...

    # LINUX-ONLY PART
    elif sys.platform.lower().startswith('linux') :
        # ...body2 for Linux...

Я нашел еще один подход, в котором каждая часть, определенная для платформы, была извлечена в свой собственный модуль, а затем импортирована условно в persistenv.py(РЕШЕНИЕ 3):

# CROSS-PLATFORM PART
def my_function1() :
    # ... body1 ...

# WINDOWS-ONLY PART
if sys.platform.lower().startswith('win') :
    from persistenv_win import my_function2

# LINUX-ONLY PART
elif sys.platform.lower().startswith('linux') :
    from persistenv_linux import my_function2

else :
    raise ImportError('Your platform is not supported')

До сих пор я сделал следующие выводы (и получил следующие вопросы):

  • РЕШЕНИЕ 2 вряд ли можно использовать, особенно если у вас есть несколько функций для платформы my_function2, my_function3, my_function4... (так как вам придется повторять тест в каждом из них)

  • РЕШЕНИЕ 1 выглядит довольно просто (без дополнительных файлов, одного теста), но мне интересно , как Python ведет себя (внутренне), если нужно вызвать "из persistenv import my_function2" ?

  • Решение 3 кажется более Pythonic (используется во встроенных реализациях, например os.path), но не может быть проблематичным, когда persistenv.py, persistenv_win.py и persistenv_linux.py являются частью одного и того же пакета (среди других модулей), который я бы импортировал глобально, выполнив "import my_package" в главном script?

4b9b3361

Ответ 1

Если вы посмотрите на стандартную библиотеку Python, вы увидите, что все три из них используются:

  • subprocess использует решения 1 и 2; есть несколько мест, где проходит тест.

  • os использует вариант решения 3 (import ... as path).

Поэтому используйте тот, который кажется наиболее подходящим и самым простым.

[Решение 1]

как Python ведет себя (внутренне), если нужно вызвать "from persistenv import my_function2"?

Он ведет себя точно так же, как и хотел. Функция, которая была определена при импорте модуля, экспортируется.

Технически модуль импортируется точно так же, как с помощью import module, а затем указанное имя просматривается в своем пространстве имен и помещается в текущий.

[Решение 3]

Не может быть проблематично, когда persistenv.py, persistenv_win.py и persistenv_linux.py являются частью одного и того же пакета (среди других модулей), которые я бы импортировал глобально, выполнив "import my_package" в главном script?

Почему это должно быть проблематично? Вы импортируете my_package в основной script, а затем главный script (или один модуль пакета) выполняет указанный импорт из модуля, зависящего от платформы. Это совершенно верно.