9

次の動作が予想されるのか、バグなのか知りたいのですが。私はCPython2.7を使用しています

ファイルx.pyを作成します

def funcA():
    print "funcA of x.py"
def funcB():
    print "funcB of x.py"

ファイルy.pyを作成します

def funcB():
    print "funcB of y.py"

ファイルtest.pyを作成します

import sys, imp
# load x.py as fff
m = imp.load_source('fff', 'x.py')
print dir(m)
print sys.modules.get('fff')
# load y.py as fff
m = imp.load_source('fff', 'y.py')
print dir(m)    
print sys.modules.get('fff')

# import and exec func
import fff
fff.funcA()
fff.funcB()
print dir(fff)

結果

['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'funcA', 'funcB']
<module 'fff' from 'x.py'>
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'funcA', 'funcB']
<module 'fff' from 'y.py'>
funcA of x.py
funcB of y.py
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'funcA', 'funcB']

私の期待は、2番目imp.load_sourceがモジュールx.pyをy.pyに完全に置き換えることでした。実際sys.modules.get('fff')には表示されます<module 'fff' from 'y.py'>が、結果のモジュールはx.pyとy.pyの組み合わせのようであり、後者が優先されます。

これは予想されることですか、それともバグですか?

編集:私のテストコードにタイプミスがありました。結果を更新しました。

4

1 に答える 1

15

これは予期される動作です。http://docs.python.org/2/library/imp.html
を参照してください

imp.load_source(名前、パス名[、ファイル])

Python ソース ファイルとして実装されたモジュールを読み込んで初期化し、そのモジュール オブジェクトを返します。モジュールがすでに初期化されている場合は、再度初期化されます。name 引数は、モジュール オブジェクトを作成またはアクセスするために使用されます。

2 番目のモジュールは最初のモジュールと同じ名前であるため、最初のモジュールは置き換えられませんが、最初のモジュールにマージされます。

ソース コードからも同じ答えが得られます。import.c
impで定義されている組み込みモジュールです。 の定義を見てみましょう
load_source

static PyObject *
load_source_module(char *name, char *pathname, FILE *fp)
{
    ......
    m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname);
    Py_DECREF(co);

    return m;
}

の単なるラッパーですPyImport_ExecCodeModuleEx

PyObject *
PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname)
{
    PyObject *modules = PyImport_GetModuleDict();
    PyObject *m, *d, *v;

    m = PyImport_AddModule(name);
    ......
    d = PyModule_GetDict(m);
    ......
    v = PyEval_EvalCode((PyCodeObject *)co, d, d);
    ......
}

今、私たちはただ集中する必要がありますPyImport_AddModule. Python はこれを使用してモジュール オブジェクトを取得します。解析されたソース ファイルは、このモジュール オブジェクトに配置されます。

PyObject *
PyImport_AddModule(const char *name)
{
    PyObject *modules = PyImport_GetModuleDict();
    PyObject *m;

    if ((m = PyDict_GetItemString(modules, name)) != NULL &&
        PyModule_Check(m))
        return m;
    m = PyModule_New(name);
    if (m == NULL)
        return NULL;
    if (PyDict_SetItemString(modules, name, m) != 0) {
        Py_DECREF(m);
        return NULL;
    }
    Py_DECREF(m); /* Yes, it still exists, in modules! */

    return m;
}

最後に、答えを見つけます。が与えられたname場合、あるモジュールがすでにこれname、つまり を持っている場合name in sys.modules、Python は新しいモジュールを作成しませんが、そのモジュールを再利用します。

于 2013-02-26T07:44:21.747 に答える