You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

不同包下同名Python模块Cython编译异常问题求助

Fix Cython Compilation Path Issue for Homonymous Modules in Different Packages

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.c and my_pkg/training/util.cpython-37m-x86_64-linux-gnu.so (or similar, depending on your Python version)
  • my_pkg/validation/util.c and my_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

火山引擎 最新活动