2015-02-01 16 views
25

Czy można utworzyć pakiet w języku Python 2.7 przy użyciu __init__.pyx (skompilowany do __init__.so)? Jeśli tak to jak? Nie miałem szczęścia, żeby to zadziałało.Pakiet Cython z __init __. Pyx: Możliwe?

Oto co próbowałem:

  • setup.py:

    #!/usr/bin/env python 
    
    from distutils.core import setup 
    from distutils.extension import Extension 
    from Cython.Distutils import build_ext 
    
    foo = Extension(name='foo.__init__', sources=['foo/__init__.pyx']) 
    bar = Extension(name='foo.bar', sources=['foo/bar.pyx']) 
    
    setup(name='foo', 
         packages = ['foo'], 
         cmdclass={'build_ext':build_ext}, 
         ext_modules = [foo, bar]) 
    
  • foo/__init__.pyx:

    import foo.bar 
    
    cpdef hello_world(): 
        print "hello world" 
        foo.bar.blah() 
    
  • foo/bar.pyx:

    cpdef blah(): 
        print "blah" 
    

Powyższe ma następujący problem:

$ python -c 'import foo; foo.hello_world()' 
Traceback (most recent call last): 
    File "<string>", line 1, in <module> 
ImportError: No module named foo 

widziałem Python issue #15576 który został ustalony przez this Hg commit. Patrząc na equivalent Git commit w Git mirror repozytorium Python Hg, widzę, że commit jest osiągalny z tagu Python v2.7.5 (jak również wszystkich kolejnych wersji v2.7.x). Czy był regres?

+0

Po prostu z ciekawości: dlaczego miałbyś to robić? – Dschoni

Odpowiedz

14

Według this really old mailing list post to działa, jeśli masz również plik __init__.py (plik __init__.py nie jest używany, ale wydaje się być niezbędne do katalogu należy traktować jako moduł, a więc plik __init__.so być załadowany).

Jeśli dodać __init__.py:

# an exception just to confirm that the .so file is loaded instead of the .py file 
raise ImportError("__init__.py loaded when __init__.so should have been loaded") 

wówczas przykład działa na Linux Python 2.7.3:

$ python -c 'import foo; foo.hello_world()' 
hello world 
blah 

ta ma wszelkie znamiona rogu przypadku buggy więc prawdopodobnie nie jest zalecane . Należy pamiętać, że w systemie Windows to nie wydają się działać dla mnie dając

ImportError: DLL load failed: %1 is not a valid Win32 application. 

Uzupełnienie (za niewielką dodatkową kontekstu):

To zachowanie nie wydaje się być wyraźnie udokumentowane. W the original description of packages z około Python 1.5 era mówią:

bez __init__.py, katalog nie jest rozpoznawana jako pakiet

i

Wskazówka: Kolejność wyszukiwania jest określona przez listę przyrostków zwróconych przez funkcja imp.get_suffixes(). Zwykle sufixy są wyszukiwane w następującej kolejności: ".so", "module.so", ".py", ".pyc". Katalogi nie występują jawnie na tej liście, ale poprzedzają wszystkie wpisy w niej.

Zaobserwowane zachowanie jest na pewno zgodne z tym — __init__.py potrzebnego do leczenia katalogu jako pakiet, ale .so plik zostanie załadowany plik .py do preferencji — ale to prawie jednoznaczne.

Z punktu widzenia Cython takie zachowanie wydaje się być wykorzystywane do kompilowania biblioteki standardowej (w którym to przypadku __init__.py zawsze były obecne) lub w testami podanymi https://github.com/cython/cython/blob/master/tests/build/package_compilation.srctree (i kilka innych przykładów zbyt). W tym przypadku plik "srctree" wygląda na rozwinięty w różne foldery zawierające __init__.py (i inne pliki), a następnie skompilowane. Możliwe, że tylko mając __init__.so po prostu nigdy nie był testowany.

+1

Czy ta sztuczka jest wymieniona w oficjalnej dokumentacji? (najwyraźniej nie było w tym wątku listy dyskusyjnej, ale być może rzeczy się zmieniły od tego czasu) –

+0

Nie sądzę. (Znalazłem to przez przypadek, a potem natknąłem się na post grupy dyskusyjnej i zrozumiałem, co zrobiłem.) Będę miał mały wygląd i zaktualizuję moją odpowiedź, jeśli znajdę lepsze źródło. Działa również z plikiem '__init __. Pyc', jak się wydaje. – DavidW

+1

Sugestie do ulepszenia: Zamiast 'assert False', podniesienie' ImportError' może być lepsze. A może są jakieś rzeczy na niskim poziomie, które można zrobić z modułem 'imp' jako fall-back w przypadku, gdyby ta sztuczka przestała działać w przyszłej wersji Pythona. –

-3

Spróbuj użyć importu względnego.

w __init__:

from . import bar

Może być również from . import foo. Nie użyłem cytonu Pythona 2 od dłuższego czasu.

Powiązane problemy