Jak uniknąć importu kołowego w Pythonie? [duplikat]

To pytanie ma już odpowiedź tutaj:

Wiem, że kwestia importu kołowego w Pythonie pojawiała się już wiele razy i czytałem te dyskusje. Komentarz, który jest wielokrotnie w tych dyskusjach jest to, że okrągły import jest oznaką złego projektu i Kod powinien być zreorganizowane, aby uniknąć przywozu okrężnego.

Mógłby mi ktoś powiedzieć jak w takiej sytuacji uniknąć importu kołowego?: Mam dwie klasy i chcę, aby każda klasa miała konstruktor (metodę), który pobiera instancję drugiej klasy i zwraca instancję klasy.

Dokładniej, jedna klasa jest zmienna, a jedna niezmienna. Potrzebna jest klasa niezmienna do hashowania, porównywania i tak dalej. Klasa mutable jest również potrzebna do robienia rzeczy. Jest to podobne do zestawów i frozensets lub do list i krotek.

Mógłbym umieścić obie definicje klas w tym samym module. Czy są jakieś inne sugestie?

Przykładem zabawki byłaby Klasa A, która ma atrybut, który jest listą, i Klasa B, która ma atrybut, który jest krotką. Następnie Klasa A ma metodę, która pobiera instancję klasy B i zwraca instancję klasy a (poprzez konwersję krotki na listę) i podobnie Klasa B ma metodę, która pobiera instancję klasy A i zwraca instancję klasy A Klasa B (poprzez konwersję listy na krotkę).

Author: Sheena, 2011-09-07

3 answers

Importuj tylko moduł, nie Importuj z modułu:

Rozważmy a.py:

import b

class A:
    def bar(self):
        return b.B()

I b.py:

import a

class B:
    def bar(self):
        return a.A()
To działa idealnie.
 67
Author: rumpel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-07 15:55:37

Rozważ następujący przykładowy pakiet Pythona, w którym a.py i b.py zależą od siebie:

/package
    __init__.py
    a.py
    b.py

Istnieje kilka sposobów na zaimportowanie modułu w Pythonie

import package.a           # Absolute import
import package.a as a_mod  # Absolute import bound to different name
from package import a      # Alternate absolute import
import a                   # Implicit relative import (deprecated, py2 only)
from . import a            # Explicit relative import

Niestety, tylko 1. i 4. opcje faktycznie działają, gdy masz okrągłe zależności (reszta podnosi ImportError lub AttributeError). Ogólnie rzecz biorąc, nie powinieneś używać 4. składni, ponieważ działa ona tylko w python2 i naraża się na zderzenie z innymi modułami innych firm. Tak naprawdę, tylko pierwszy składnia jest gwarantowana. Jednak nadal masz kilka opcji, gdy masz do czynienia z zależnościami kołowymi.

EDIT: problemy ImportError i AttributeError występują tylko w python 2. W Pythonie 3 Maszyna importowa została przepisana i wszystkie z tych poleceń importu (z wyjątkiem 4) będzie działać, nawet z zależności kołowe.

Użyj Importu Bezwzględnego

Po prostu użyj pierwszej składni importu powyżej. Minusem tej metody jest to, że import nazwy mogą uzyskać super długie dla dużych pakietów.

W a.py

import package.b

W b.py

import package.a

Odroczyć import na później

Widziałem tę metodę używaną w wielu pakietach, ale nadal wydaje mi się to trudne, i nie podoba mi się, że nie mogę spojrzeć na górę modułu i zobaczyć wszystkich jego zależności, muszę przejść przeszukanie wszystkich funkcji, jak również.

W a.py

def func():
    from package import b

W b.py

def func():
    from package import a

Umieścić wszystkie import w centralnym moduł

To również działa, ale ma ten sam problem co pierwsza metoda, gdzie wszystkie wywołania pakietu i podmodułu otrzymują super długie . Ma również dwie główne wady-zmusza wszystkie moduły podrzędne do zaimportowania, nawet jeśli używasz tylko jednego lub dwóch, a nadal nie możesz spojrzeć na żadne z modułów podrzędnych i szybko zobaczyć ich zależności na górze, musisz przejść do przesiewania funkcji.

W __init__.py

from . import a
from . import b

W a.py

import package

def func():
    package.b.some_object()

W b.py

import package

def func():
    package.a.some_object()

Więc to są Twoje opcje (i wszystkie są do bani IMO). Szczerze mówiąc, wydaje się to być rażącym błędem w maszynach importujących python, ale to tylko moje zdanie.

 114
Author: Brendan Abel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 01:08:49

Wykonujemy kombinację importu bezwzględnego i funkcji dla lepszego odczytu i krótszych ciągów dostępu.

  • zaleta: krótsze ciągi dostępu w porównaniu z czystym importem absolutnym
  • wada: trochę więcej kosztów z powodu dodatkowego wywołania funkcji

Main/sub/a.py

import main.sub.b
b_mod = lambda: main.sub.b

class A():
    def __init__(self):
        print('in class "A":', b_mod().B.__name__)

Main/sub/b.py

import main.sub.a
a_mod = lambda: main.sub.a

class B():
    def __init__(self):
        print('in class "B":', a_mod().A.__name__)
 4
Author: Christian Haintz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-08 13:30:40