Loading

[PYTHON] import foo.bar 和 from foo import bar 有何不同

项目脚本使用python编写,为了减少单文件代码行数,便于逻辑功能拆分和管理,项目中大量使用了组件方式对文件进行拆分和导入,比如原client/entities/Space.py文件有两千多行,糅杂了各种逻辑,维护起来很不方便,现在将其抽取出来放到client/spacemembers/文件夹,并在Space.py中注入。

file client/spacemembers/__init__.py:

def importall():  # import同目录下的多个文件
    return (
        __import__('CSpaceData', globals()),
        __import__('CSpaceBattle', globals()),
        __import__('CSpaceAvatar', globals()),
        ...... ,
    )

在 client/entities/Space.py 中注入代码:

from client import spacemembers

@Components(*spacemembers.importall())  # 这里由自定义的Components装饰器完成代码注入
class Space(object):
    pass

这种方式让代码组织更有条理,但在使用项目的reload脚本进行热更新的时候确报错了:

......client\spacemembers\__init__.py:11: RuntimeWarning: Parent module 'client.spacemembers' not found while handling absolute import __import__("CSpaceData", globals()),

然后发现将上面的import和注入改为下面即可解决:

import client.spacemembers

@Components(*client.spacemembers.importall())
class Space(object):
    pass

那么 import foo.bar 和 from foo import bar这两种形式的import到底有何不同呢?你去stackoverflow和google搜索都找不到答案,大多说些都说些方便性和代码规范之类的。直到你看到python的源码:

/* Return the package that an import is being performed in.  If globals comes
   from the module foo.bar.bat (not itself a package), this returns the
   sys.modules entry for foo.bar.  If globals is from a package's __init__.py,
   the package's entry in sys.modules is returned, as a borrowed reference.
   The *name* of the returned package is returned in buf, with the length of
   the name in *p_buflen.
   If globals doesn't come from a package or a module in a package, or a
   corresponding entry is not found in sys.modules, Py_None is returned.
*/
static PyObject *
get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level)
{
    static PyObject *namestr = NULL;
    static PyObject *pathstr = NULL;
    static PyObject *pkgstr = NULL;
    PyObject *pkgname, *modname, *modpath, *modules, *parent;
    int orig_level = level;

    ........

原来,正如错误信息提示的那样,项目的reload脚本在调用importall时将其parent记录为foo.bar,但使用from foo import bar进行import时globals()中并没有foo.bar

https://github.com/santazhang/Python-2.7.6/blob/a56836aa2cfabd873518358aa011857d6bb76283/Lib/ihooks.py#L415
https://github.com/santazhang/Python-2.7.6/blob/a56836aa2cfabd873518358aa011857d6bb76283/Python/import.c#L2310

posted @ 2026-02-02 14:46  dylanchu  阅读(17)  评论(0)    收藏  举报