Mój pakiet Pythona zależy od biblioteki zewnętrznej dla kilku funkcji. Jest to pakiet nie-python i może być trudny do zainstalowania, więc chciałbym, aby użytkownicy nadal mogli korzystać z mojego pakietu, ale nie zawiedziemy za pomocą dowolnych funkcji, które zależą od tego pakietu innych niż Python.

Jaka jest standardowa praktyka dla tego? Mogę importować pakiet innych niż Python wewnątrz metod, które go używają, ale naprawdę nienawidzę tego robić

Moja aktualna konfiguracja:

myInterface.py
myPackage/
--classA.py
--classB.py

Skrypt interfejsów myInterface.py Imports classA i classB i classB Importuje pakiet nie-Python. Jeśli import nie powiedzie się, wydrukuję ostrzeżenie. Jeśli nazywa się myMethod, a pakiet nie jest zainstalowany, będzie jakiś błąd, ale nie złapię go nigdzie, ani nie ostrzegam użytkownika.

classB jest importowany za każdym razem, gdy skrypt interfejsu nazywa się, więc nie mogę mieć nic nie, dlatego włączyłem pass. Jak powiedziałem powyżej, mogłem importować wewnątrz metody i mieć tam zawieść, ale naprawdę lubię utrzymywać cały mój import w jednym miejscu.

Z klasyb.py.py.

try:
    import someWeirdPackage
except ImportError:
    print("Cannot import someWeirdPackage")
    pass

class ClassB():
    ...
    def myMethod():
        swp = someWeirdPackage()
        ...
3
Sal 29 czerwiec 2017, 19:15

4 odpowiedzi

Najlepsza odpowiedź

Nie jestem pewien, że w tej sytuacji jest jakakolwiek najlepsza praktyka, ale przedefiniowałem funkcję, jeśli nie jest obsługiwane:

def warn_import():
    print("Cannot import someWeirdPackage")

try:
    import someWeirdPackage
    external_func = someWeirdPackage
except ImportError:
    external_func = warn_import


class ClassB():
    def myMethod(self):
        swp = external_func()


b = ClassB()
b.myMethod()
3
charli 29 czerwiec 2017, 16:46

Możesz także użyć podanych poniżej podejścia do przezwyciężenia problemu.

class UnAvailableName(object):

    def __init__(self, name):
        self.target = name

    def __getattr_(self, attr):
        raise ImportError("{} is not available.".format(attr))


try:
    import someWeirdPackage
except ImportError:
    print("Cannot import someWeirdPackage")
    someWeirdPackage = someWeirdPackage("someWeirdPackage")

class ClassB():
    def myMethod():
        swp = someWeirdPackage.hello()

a = ClassB()
a.myMethod()
0
Mangu Singh Rajpurohit 29 czerwiec 2017, 16:55

Możesz utworzyć dwie oddzielne zajęcia dla dwóch przypadków. Pierwsza zostanie użyta, gdy pakiet istnieje. Druga użyje, gdy pakiet nie istnieje.

class ClassB1():
    def myMethod(self):
        print("someWeirdPackage exist")
        # do something

class ClassB2(ClassB1):
    def myMethod(self):
        print("someWeirdPackage does not exist")
        # do something or raise Exception

try:    
    import someWeirdPackage
    class ClassB(ClassB1):
        pass
except ImportError:
    class ClassB(ClassB2):
        pass
0
napuzba 29 czerwiec 2017, 16:55

Jeśli importujesz tylko jedną bibliotekę zewnętrzną, pójdę na coś wzdłuż tych linii:

try:
    import weirdModule
    available = True
except ImportError:
    available = False

def func_requiring_weirdmodule():
    if not available:
        raise ImportError('weirdModule not available')
    ...

Sprawdzanie warunkowego i błędu jest potrzebne tylko wtedy, gdy chcesz podać bardziej opisowe błędy. Jeśli nie możesz go pominąć i pozwolić Python rzucić odpowiedni błąd podczas próby wywołania modułu nie importowanego, jak w bieżącym konfiguracji.

Jeśli wiele funkcji użyje weirdModule, można owinąć sprawdzanie do funkcji:

def require_weird_module():
    if not available:
        raise ImportError('weirdModule not available')

def f1():
    require_weird_module()
    ...

def f2():
    require_weird_module()
    ...

Z drugiej strony, jeśli masz wiele bibliotek, które mają być importowane przez różne funkcje, możesz je załadować dynamicznie. Chociaż nie wygląda ładnie, Python buforuje ich i nie ma w tym nic złego. Używałbym importlib

import importlib

def func_requiring_weirdmodule():
    weirdModule = importlib.import_module('weirdModule')

Ponownie, jeśli wiele funkcji importuje skomplikowane moduły zewnętrzne, możesz je owinąć do:

def import_external(name):
    return importlib.import_module(name)

def f1():
    weird1 = import_external('weirdModule1')


def f2():
    weird2 = import_external('weirdModule2')

I ostatni, możesz utworzyć przewóz, aby zapobiec importowaniu tego samego modułu dwukrotnie, coś wzdłuż linii:

class Importer(object):

    __loaded__ = {}

    @staticmethod
    def import_external(name):
        if name in Importer.__loaded__:
            return Importer.__loaded__[name]
        mod = importlib.import_module(name)
        Importer.__loaded__[name] = mod
        return mod

def f1():
    weird = Importer.import_external('weird1')


def f2():
    weird = Importer.import_external('weird1')

Chociaż jestem pewien, że importowała buforowanie za kulisami i tak naprawdę nie potrzebujesz ręcznego buforowania.


Krótko mówiąc, chociaż wygląda brzydko, nie ma nic złego w importowaniu modułów dynamicznie w Pythonie. W rzeczywistości wiele bibliotek polegają na tym. Z drugiej strony, jeśli jest to tylko dla specjalnego przypadku 3 metod uzyskiwania dostępu do 1 funkcji zewnętrznej, użyj podejścia lub mojego pierwszego w przypadku, gdy nie możesz dodać niestandardowej obsługi scepty.

4
Imanol Luengo 29 czerwiec 2017, 16:58