Подтвердить что ты не робот

Передать переменную при импорте

Скажем, у вас есть трудоемкая работа, когда сначала импортируется модуль/класс. Эта функциональность зависит от переданной переменной. Это нужно делать только при загрузке модуля/класса. Все экземпляры класса могут затем использовать результат.

Например, я использую rpy2:

import rpy2.robjects as robjects

PATH_TO_R_SOURCE = ## I need to pass this
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time

class SomeClass:
  def __init__(self, aCurve):
    self._curve = aCurve

  def processCurve(self):
    robjects.r['someRFunc'](robjects.FloatVector(self._curve))

Я застрял, создав функцию уровня модуля, которую я вызываю, чтобы выполнить работу?

import someClass
someClass.sourceRStuff(PATH_TO_R_SOURCE)
x = someClass.SomeClass([1,2,3,4])
etc...

Мне здесь что-то не хватает. Спасибо.

4b9b3361

Ответ 1

Наличие функции init модуля не является неслыханным. Pygame делает это для функций инициализации sdl. Так что да, ваш лучший выбор, вероятно,

import someModule
someModule.init(NECESSARY_DATA)
x = someModule.someClass(range(1, 5))

Ответ 2

Мне нужно было сделать что-то подобное для моего проекта. Если вы не хотите полагаться на вызов script для запуска функции инициализации, вы можете добавить свой собственный встроенный Python, который затем доступен для всех модулей во время выполнения.

Будьте осторожны, чтобы назвать свой встроенный что-то уникальное, что вряд ли вызовет столкновение пространства имен (например, myapp_myvarname).

run.py

import __builtin__
__builtin__.myapp_PATH_TO_R_SOURCE = 'path.to.r.source'
import someClass

модуль someClass.py

import rpy2.robjects as robjects
import __builtin__

if hasattr(__builtin__, "myapp_PATH_TO_R_SOURCE"):
    PATH_TO_R_SOURCE = __builtin__.myapp_PATH_TO_R_SOURCE
else:
    PATH_TO_R_SOURCE = ## Some default value or Null for Exception handling
robjects.r.source(PATH_TO_R_SOURCE, chdir = True)

...

Это хорошо работает для переменных, которые могут иметь значение по умолчанию, но вы хотите разрешить переопределение во время импорта. Если переменная __builtin__ не установлена, она будет использовать значение по умолчанию.

Изменить: Некоторые считают это примером "Monkey patching". Для более элегантного решения без патча обезьяны см. Мой другой ответ.

Ответ 3

Невозможно передать переменную при импорте.

Некоторые идеи:

  • заставить модуль получить переменную из вызывающего модуля с помощью проверки; не очень pythonic
  • используйте функцию Init для модуля, это лучший способ

Ответ 4

Если задан только один элемент конфигурации, я обнаружил, что переопределение python __builtin__ работает нормально, но это пример "Monkey patching" , на кого некоторые недовольны.

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

myconfig/__ init__.py:

PATH_TO_R_SOURCE   = '/default/R/source/path'
OTHER_CONFIG_ITEM  = 'DEFAULT'
PI                 = 3.14

mymodule/__ init__.py:

import myconfig

PATH_TO_R_SOURCE = myconfig.PATH_TO_R_SOURCE
robjects.r.source(PATH_TO_R_SOURCE, chdir = True) ## this takes time

class SomeClass:
  def __init__(self, aCurve):
    self._curve = aCurve

if myconfig.VERSION is not None:
  version = myconfig.VERSION
else:
  version = "UNDEFINED"

two_pi = myconfig.PI * 2

И вы можете изменить поведение своего модуля во время выполнения из оболочки:

run.py:

import myconfig

myconfig.PATH_TO_R_SOURCE = 'actual/path/to/R/source'
myconfig.PI = 3.14159
# we can even add a new configuration item that isn't present in the original myconfig:
myconfig.VERSION="1.0"

import mymodule
print "Mymodule.two_pi = %r" % mymodule.two_pi
print "Mymodule.version is %s" % mymodule.version

Вывод:

> Mymodule.two_pi = 6.28318
> Mymodule.version is 1.0

Ответ 5

Нет, вы не застряли в функции уровня модуля, это просто лучший вариант. Вы также можете использовать встроенные декодеры staticmethod или classmethod, чтобы сделать его методом на someSclass, который можно вызвать до того, как он будет создан.

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

Ответ 6

Пара других вариантов, которые могут достичь вашей цели (хотя функция init(), вероятно, более чистая):

  • Использовать переменную среды
  • Используйте отдельный модуль M для хранения этой переменной, которую установил бы импортер. Затем импортированный модуль может знать, где найти M, или может полагаться на sys.meta_path для его получения.

Ответ 7

Есть два решения, о которых я могу думать, оба из которых являются очень похожими на работу решениями. Первый заключается в том, чтобы убрать импорт и запустить ваш script следующим образом

sys.argv [1] = "argument 1"
sys.argv [2] = "argument 2"
execfile("/path/to/dependency.py")  #depreciated in python 3.x

Второй способ заключается в том, чтобы поместить ваши аргументы во внешний временный файл, а затем прочитать из этого файла в зависимости.

Ответ 8

Вы можете воспользоваться прокси-сервером, который реализует ленивую загрузку?

Проверьте Active State Lazy Module Imports".