2015-02-01 10 views
25

Ist es möglich, ein Python 2.7-Paket mit __init__.pyx (kompiliert zu __init__.so) zu erstellen? Wenn das so ist, wie? Ich hatte kein Glück, es zur Arbeit zu bringen. HierCython-Paket mit __init __. Pyx: Möglich?

ist, was ich versucht habe:

  • 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" 
    

Die oben hat folgendes Verhalten:

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

ich Python issue #15576 sah, die von this Hg commit wurde behoben. Betrachtet man die equivalent Git commit in der Git mirror des Python Hg Repository, sehe ich, dass das Commit von der Python v2.7.5-Tag (sowie alle nachfolgenden v2.7.x-Versionen) erreichbar ist. Gab es eine Regression?

+0

Nur aus Neugier: Warum sollten Sie das tun? – Dschoni

Antwort

14

Nach this really old mailing list post funktioniert es, wenn Sie auch eine __init__.py-Datei (die __init__.py Datei nicht verwendet wird, sondern scheint notwendig zu sein, für das Verzeichnis als Modul behandelt zu werden, und damit die __init__.so-Datei geladen werden).

Wenn ich hinzufügen __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") 

dann zB auf Linux Python funktioniert 2.7.3:

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

Dies hat alle Anzeichen für einen Buggy Ecke Fall so wahrscheinlich nicht zu empfehlen . Beachten Sie, dass unter Windows dies nicht für mich

geben zu funktionieren scheint
ImportError: DLL load failed: %1 is not a valid Win32 application. 

Nachtrag (für ein wenig mehr Kontext):

Dieses Verhalten scheint nicht explizit dokumentiert werden. In the original description of packages von Python 1.5 Ära sagen sie:

ohne __init__.py, ein Verzeichnis nicht als Paket

und

Tipp erkannt wird: die Suchreihenfolge wird von der Liste der Suffixe bestimmt wieder durch die Funktion imp.get_suffixes(). Normalerweise werden die Suffixe in der folgenden Reihenfolge durchsucht: ".so", "module.so", ".py", ".pyc". Verzeichnisse erscheinen nicht explizit in dieser Liste, sondern gehen allen Einträgen voraus.

Das beobachtete Verhalten ist sicherlich im Einklang mit diesen — __init__.py benötigte ein Verzeichnis als Paket zu behandeln, aber .so Datei in Voreinstellungsdatei .py — geladen wird, aber es ist kaum eindeutig.

Aus Cython Sicht dieses Verhalten die Standard-Bibliothek zu erstellen (in diesem Fall __init__.py wäre immer vorhanden gewesen), oder in den Testfällen gegeben https://github.com/cython/cython/blob/master/tests/build/package_compilation.srctree (und ein paar anderen Beispiele zu) verwendet werden, scheint worden. In diesen scheint die "srctree" -Datei in eine Vielzahl von Ordnern, die __init__.py (und andere Dateien) enthalten, zu kompilieren. Es ist möglich, dass nur __init__.so einfach nie getestet wurde.

+1

Ist dieser Trick in der offiziellen Dokumentation erwähnt? (Es war anscheinend nicht zur Zeit des Mailinglisten-Threads, aber vielleicht haben sich die Dinge seitdem geändert) –

+0

Ich glaube nicht. (Ich habe es zufällig gefunden und bin kurz darauf auf den Newsgroup-Post gestoßen und habe bemerkt, was ich getan habe.) Ich werde ein wenig nachsehen und meine Antwort aktualisieren, wenn ich eine bessere Quelle finden kann. Es funktioniert auch mit einer Datei "__init __. Pyc". – DavidW

+1

Verbesserungsvorschläge: Anstatt "Assert False" zu setzen, ist es möglicherweise besser, "ImportError" anzuheben. Oder vielleicht gibt es etwas Low-Level-Zeug, das mit dem 'imp'-Modul als Fall-Back gemacht werden kann, falls dieser Trick in einer zukünftigen Version von Python nicht mehr funktioniert. –

-3

Versuchen Sie, einen relativen Import zu verwenden.

in __init__:

from . import bar

könnte auch from . import foo sein. Habe Python 2 Cython schon lange nicht mehr benutzt.