Какая практика Python полезна для импорта и предложения дополнительных функций? - PullRequest
25 голосов
/ 19 февраля 2009

Я пишу часть программного обеспечения на GitHub. В основном это иконка в трее с некоторыми дополнительными функциями. Я хочу предоставить рабочий кусок кода, фактически не заставляя пользователя устанавливать то, что по сути является зависимостями для дополнительных функций, и я на самом деле не хочу импортировать вещи, которые я не собираюсь использовать, поэтому я думал, что такой код будет хорошее решение ":

---- IN LOADING FUNCTION ----
features = []

for path in sys.path:
       if os.path.exists(os.path.join(path, 'pynotify')):
              features.append('pynotify')
       if os.path.exists(os.path.join(path, 'gnomekeyring.so')):
              features.append('gnome-keyring')

#user dialog to ask for stuff
#notifications available, do you want them enabled?
dlg = ConfigDialog(features)

if not dlg.get_notifications():
    features.remove('pynotify')


service_start(features ...)

---- SOMEWHERE ELSE ------

def service_start(features, other_config):

        if 'pynotify' in features:
               import pynotify
               #use pynotify...

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

if 'pynotify' in features:
    #gtk checkbox
else:
    #gtk label reading "Get pynotify and enjoy notification pop ups!"

Но если это, скажем, макинтош, откуда мне знать, что я не отправляю пользователя в погоне за диким гусем в поисках зависимости, которую он никогда не сможет заполнить?

Вторая проблема:

if os.path.exists(os.path.join(path, 'gnomekeyring.so')):

вопрос. Могу ли я быть уверен, что файл всегда называется gnomekeyring.so во всех дистрибутивах Linux?

Как другие люди тестируют эти функции? Проблема с основным

try:
    import pynotify
except:
    pynotify = disabled

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

Так что люди думают, что это лучший способ решить эту проблему?

Ответы [ 3 ]

41 голосов
/ 19 февраля 2009

Метод try: не обязательно должен быть глобальным - его можно использовать в любой области, и поэтому модули могут быть «загружены ленивыми» во время выполнения. Например:

def foo():
    try:
        import external_module
    except ImportError:
        external_module = None 

    if external_module:
        external_module.some_whizzy_feature()
    else:
        print("You could be using a whizzy feature right now, if you had external_module.")

Когда ваш скрипт запущен, не будет предпринято никаких попыток загрузить external_module. При первом вызове foo(), external_module (если доступно) загружается и вставляется в локальную область функции. Последующие вызовы foo() повторно вставляют external_module в его область без необходимости перезагрузки модуля.

В общем, лучше всего разрешить Python обрабатывать логику импорта - он делал это некоторое время. : -)

12 голосов
/ 19 февраля 2009

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

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

0 голосов
/ 19 февраля 2009

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

...