Moja otázka je veľmi podobná toto, ale v mojom prípade prijatá odpoveď nezdobí všetky funkcie v balení, keď sa používajú v rámci balíka a ja si nie som istý prečo.
Napríklad mám nastavený projekt takto:
project/
package/
__init__.py
module_a.py
module_b.py
main.py
__init__.py
from .module_a import *
from .module_b import *
import types
# This is the decorator that will be used
from functools import lru_cache
for name, obj in list(globals().items()):
if isinstance(obj, types.FunctionType):
globals()[name] = lru_cache(maxsize=100)(obj)
module_a.py
from .module_b import b
def a(arg):
return b
module_b.py
def b(arg):
return arg
main.py
import package
print(package.a.cache_info())
print(package.a(None).cache_info())
print(package.b.cache_info())
Keď sa balík importuje, __init__.py
zdobí funkcie v globals
v poriadku, keď prechádzate kódom. Ak však vykonám main.py
Mám nasledujúcu chybu:
C:UserspbreachAnaconda3python.exe C:/Users/pbreach/PycharmProjects/project/main.py
Traceback (most recent call last):
CacheInfo(hits=0, misses=0, maxsize=100, currsize=0)
File "C:/Users/pbreach/PycharmProjects/project/main.py", line 4, in <module>
print(package.a(None).cache_info())
AttributeError: "function" object has no attribute "cache_info"
Čo by to znamenalo b
nie je ozdobený, ak je dovezený module_b
v module_a
.
Prečo k tomu dochádza len v druhom riadku? Čo by to mohlo byť?
Som v pohode s robiť zdobenie buď pri dovoze do __init__.py
alebo v main.py
, ale radšej by nemusel aplikovať dekoratéra vo vnútri každého modulu package
ako v mojom prípade je ich pomerne málo.
Myslím si, že problémom je, že globals
v __init__.py
je iný menný priestor ako kedykoľvek b
sa importuje do module_a
znamená, že existujú dve rôzne inštancie rovnakej funkcie. Existuje nejaká cesta okolo toho?
odpovede:
1 pre odpoveď č. 1Dovážíte b
z module_b
v module_a
skôr, než dostanete šancu ju ozdobiť functools.lru_cache
.
Vidím len jedinú životaschopnú alternatívu, ktorá je najprv explicitne zdobená funkciami, ktoré sa dovážajú a používajú v iných submodulách a potom aplikujú dekoratér na všetky ostatné funkcie.
Pomocou svojho príkladu najprv ozdobte b
z module_b
a potom ozdobíme zvyšok:
from package import module_b
import types
# This is the decorator that will be used
from functools import lru_cache
module_b.b = lru_cache(maxsize=100)(module_b.b)
from .module_a import *
from .module_b import *
for name, obj in list(globals().items()):
if isinstance(obj, types.FunctionType):
globals()[name] = lru_cache(maxsize=100)(obj)
Ďalšou možnosťou, ako som uviedol v komentári, by bolo použiť if
klauzuly vo vnútri modulov, ktoré obsahujú funkcie, ktoré sú zahrnuté v iných moduloch, kde by sa tam nachádzalo balenie.
Takže v module_b.py
mohli by ste vykonať niečo takéto:
if __name__ != "__main__":
from functools import lru_cache
b = lru_cache(b)
toto len zachytí prípad, keď modul nie je spustený ako __main__
, Teraz, keď iný modul obsahuje tento modul a jeho telo sa spúšťa, obal sa bude vykonávať tu namiesto __init__.py
.