不同包下同名Python模块Cython编译异常问题求助
I've run into this exact issue before when dealing with Cython and modules that share the same name across different subpackages. Let's break down why this happens and how to fix it properly.
Why This Happens
When you use a wildcard like "*" or don't specify the full package-qualified module name in your Extension definitions, distutils can't properly map each module to its corresponding package directory. For homonymous modules (like util.py in both training and validation), it ends up misplacing the final .so file in the root directory because it can't distinguish between the two modules by name alone.
Also, I noticed a typo in your original code: you wrote ./my_pgk/*/*.py instead of ./my_pkg/*/*.py (missing an 'e' in my_pkg). That might have contributed to unexpected behavior too.
The Solution: Explicitly Define Extensions with Full Module Names
Instead of relying on wildcards or vague module names, you need to create an Extension for each module using its full package-qualified name (e.g., my_pkg.training.util instead of just util). This tells Cython and distutils exactly where to place the compiled .so file.
Option 1: Automatically Generate Extensions (Scalable for Many Modules)
Use glob to recursively find all your .py files, then convert their paths to full module names:
import glob from distutils.core import setup from Cython.Build import cythonize from distutils.extension import Extension def get_cython_extensions(): extensions = [] # Recursively find all .py files in my_pkg for py_path in glob.glob("./my_pkg/**/*.py", recursive=True): # Convert file path to full module name: # ./my_pkg/training/util.py → my_pkg.training.util module_name = py_path.replace("./", "").replace("/", ".").rstrip(".py") extensions.append(Extension(module_name, [py_path])) return extensions setup( name="my_project", ext_modules=cythonize( get_cython_extensions(), compiler_directives={'language_level': "3"} ), )
Option 2: Manually Define Extensions (For Smaller Projects)
If you only have a few modules to compile, you can list them explicitly with full names:
from distutils.core import setup from Cython.Build import cythonize from distutils.extension import Extension ext_modules = [ Extension("my_pkg.training.util", ["./my_pkg/training/util.py"]), Extension("my_pkg.validation.util", ["./my_pkg/validation/util.py"]), ] setup( name="my_project", ext_modules=cythonize( ext_modules, compiler_directives={'language_level': "3"} ), )
Verify the Fix
Run your compile command as before:
python compile.py build_ext --inplace
You should now see:
my_pkg/training/util.candmy_pkg/training/util.cpython-37m-x86_64-linux-gnu.so(or similar, depending on your Python version)my_pkg/validation/util.candmy_pkg/validation/util.cpython-37m-x86_64-linux-gnu.so
No extra .so files will be generated in the root directory anymore.
This approach works because each Extension has a unique, fully qualified name that maps directly to the package structure. distutils uses this name to determine the correct output path for the compiled .so file, eliminating conflicts between homonymous modules.
内容的提问来源于stack exchange,提问作者Nikolay Hüttenberend




