__package__ Нет при импорте модуля Python - PullRequest
7 голосов
/ 14 декабря 2010

Я хочу импортировать модули динамически, следующим образом:

Я создаю папку с именем pkg с такой структурой:

pkg
   |__init__.py
   |foo.py

В заголовке __init__.py добавьтеэтот код fragement:

pkgpath = os.path.dirname(pkg.__file__);
for module in pkgutil.iter_modules([pkgpath]):
     __import__(module[1], locals(), globals());
     m = sys.modules[module[1]];
     print m.__package__;

Я обнаружил, что m.__package__ - это None на случай, если в foo.py нет операторов импорта, но если я добавлю простой оператор импорта, такой как:

затем m.__package__ - это "pkg", которое является правильным именем пакета.почему это происходит?

Как импортировать модуль и обеспечить его правильный атрибут пакета?

1 Ответ

9 голосов
/ 15 декабря 2010

Атрибут __package__, как вы заметили, не установлен согласованно. (Более подробная информация внизу.) Однако вы всегда должны иметь возможность получить имя пакета, взяв все до последнего периода в атрибуте __name__ модуля. Например. mymod.__name__.rpartition('.')[0]. Для вашей цели, вероятно, проще просто построить иерархию пакетов / модулей при загрузке модулей.

Например, вот функция, которая загружает все модули в пакете, рекурсивно загружает модули в подпакеты и т. Д. (Здесь я предполагаю, что вы не возражаете против функций с побочными эффектами ...)

import sys
import pkgutil
from os.path import dirname

def loadModules(pkg):
    pkg._modules = []

    pkgname = pkg.__name__
    pkgpath = dirname(pkg.__file__)

    for m in pkgutil.iter_modules([pkgpath]):
        modulename = pkgname+'.'+m[1]
        __import__(modulename, locals(), globals())
        module = sys.modules[modulename]

        module._package = pkg
        # module._packageName = pkgname

        pkg._modules.append(module)
        if dirname(module.__file__) == pkgpath:
            module._isPackage = False
        else:
            module._isPackage = True
            loadModules(module)


def modName(mod):
    return mod.__name__.rpartition('.')[-1]

def printModules(pkg, indent=0):
    print '\t'*indent, modName(pkg), ':'
    indent += 1
    for m in pkg._modules:
        if m._isPackage:
            printModules(m, indent)
        else:
            print '\t'*indent, modName(m)

import dummypackage
loadModules(dummypackage)
printModules(dummypackage)

Пример вывода:

dummypackage :
    modx
    mody
    pack1 :
        mod1
        pack2 :
            mod2

Дополнительная информация:

Атрибут __package__ используется системой импорта для упрощения относительного импорта в пакет. Подробнее см. PEP 366 . Чтобы (предположительно) сэкономить время при загрузке модулей, атрибут устанавливается только в том случае, если загруженный модуль импортирует другой модуль.

...