Mam bibliotekę, która może użyć dwóch modułów; Jeden jest szybki, ale dostępny tylko w systemie Linux i MacOS, drugi jest wolniejszy, ale jest wielowarstwowa. Moim rozwiązaniem było uczynienie biblioteki kompatybilnej z obu i mieć coś takiego:

try:
    import fastmodule
except ImportError:
    import slowmodule

Teraz chcę porównać czas biblioteki podczas korzystania z jednego modułu. Czy jest jakiś sposób maskowania fastmodule bez zmiany kodu źródłowego (tj. W notebooku Jupsytera), w środowisku, w którym obie moduły są zainstalowane, dzięki czemu używany jest slowmodule?

1
rmmr 21 marzec 2020, 18:16

1 odpowiedź

Najlepsza odpowiedź

To trochę hacku, ale tutaj idzie:
Możesz napisać własny importer i zarejestrować go (zauważ, że jest to Python 3 specyficzny, Python 2 miał inny interfejs API):

import sut
import functools
import importlib
import sys


def use_slow(f):
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        ImportRaiser.use_slow = True
        if 'fastmodule' in sys.modules:
            del sys.modules['fastmodule']  # otherwise it will remain cached
        importlib.reload(sut)
        f(*args, **kwargs)

    return wrapped


def use_fast(f):
    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        ImportRaiser.use_slow = False
        importlib.reload(sut)
        f(*args, **kwargs)

    return wrapped


class ImportRaiser:
    use_slow = False

    def find_spec(self, fullname, path, target=None):
        if fullname == 'fastmodule':
            if self.use_slow:
                raise ImportError()


sys.meta_path.insert(0, ImportRaiser())

@use_fast
def test_fast():
    # test code


@use_slow
def test_slow():
    # test code

Tutaj sut jest testem modułu, który musisz przeładować, aby zmienić zachowanie. Dodałem dekoratorzy do odpowiadania, ale oczywiście można to zrobić za pomocą funkcji lub w konfiguracji testowej.

Jeśli użyjesz wersji powolnej, fastmodule podniesie ImportError na imporcie i zamiast tego użyje slowmodule. W przypadku "Szybko" wszystkie działa jak zwykle.

1
MrBean Bremen 24 marzec 2020, 20:34