Импорт классов из разных файлов в подкаталог
Здесь структура, с которой я работаю:
directory/
script.py
subdir/
__init__.py
myclass01.py
myclass02.py
Что я хочу сделать, это импортировать в script.py классы, определенные в myclass01.py
и myclass02.py
. Если я это сделаю:
from subdir.myclass01 import *
Он отлично работает для класса, определенного в myclass01.py
. Но с этим решением, если в subdir
есть несколько классов, определенных в разных файлах, и я хочу их импортировать, мне пришлось бы набирать одну строку для каждого файла. Для этого должен быть ярлык. Я пробовал:
from subdir.* import *
Но это не сработало.
EDIT: вот содержимое файлов:
Это __init__.py
(используя __all__
, как предлагал Апалала):
__all__ = ['MyClass01','MyClass02']
Это myclass01.py
:
class MyClass01:
def printsomething():
print 'hey'
Это myclass02.py
:
class MyClass02:
def printsomething():
print 'sup'
Это script.py
:
from subdir import *
MyClass01().printsomething()
MyClass02().printsomething()
Это трассировка, которую я получаю, когда пытаюсь запустить script.py
:
File "script.py", line 1, in <module>
from subdir import *
AttributeError: 'module' object has no attribute 'MyClass01'
Ответы
Ответ 1
Хотя имена, используемые там, отличаются от того, что показано в структуре справочника вопросов, вы можете использовать мой ответ на вопрос под названием Namespacing и classes. Показанный там __init__.py
также допустил бы, чтобы текст usepackage.py
script был записан таким образом (package
отображается в subdir
в вашем вопросе и Class1
до myclass01
и т.д.):
from package import *
print Class1
print Class2
print Class3
Версия (обновлено):
К сожалению, код в моем другом ответе не совсем делает то, что вы хотите - он только автоматически импортирует имена любых подмодулей пакетов. Чтобы импортировать именованные атрибуты из каждого подмодуля, требуется еще несколько строк кода. Здесь измененная версия пакета __init__.py
file (который также работает в Python 3.4.1):
def _import_package_files():
""" Dynamically import all the public attributes of the python modules in this
file directory (the package directory) and return a list of their names.
"""
import os
exports = []
globals_, locals_ = globals(), locals()
package_path = os.path.dirname(__file__)
package_name = os.path.basename(package_path)
for filename in os.listdir(package_path):
modulename, ext = os.path.splitext(filename)
if modulename[0] != '_' and ext in ('.py', '.pyw'):
subpackage = '{}.{}'.format(package_name, modulename) # pkg relative
module = __import__(subpackage, globals_, locals_, [modulename])
modict = module.__dict__
names = (modict['__all__'] if '__all__' in modict else
[name for name in modict if name[0] != '_']) # all public
exports.extend(names)
globals_.update((name, modict[name]) for name in names)
return exports
if __name__ != '__main__':
__all__ = ['__all__'] + _import_package_files() # '__all__' in __all__
В качестве альтернативы вы можете поместить указанное выше в отдельный файл .py-модуля в каталог пакета и использовать его из пакета __init__.py
следующим образом:
if __name__ != '__main__':
from ._import_package_files import * # defines __all__
__all__.remove('__all__') # prevent export (optional)
Независимо от того, что вы называете файлом, это должно быть то, что начинается с символа подчеркивания _
, поэтому он не рекурсивно пытается import
.
Ответ 2
Ваш лучший вариант, хотя, вероятно, не самый лучший стиль, заключается в том, чтобы импортировать все в пространство имен пакетов:
# this is subdir/__init__.py
from myclass01 import *
from myclass02 import *
from myclass03 import *
Затем в других модулях вы можете импортировать то, что хотите прямо из пакета:
from subdir import Class1
Ответ 3
Я знаю, что прошло пару месяцев с момента ответа на этот вопрос, но я искал то же самое и перебегал через эту страницу. Я был не очень доволен выбранным ответом, поэтому в итоге я написал свое собственное решение и думал, что поделюсь им. Вот что я придумал:
# NOTE: The function name starts with an underscore so it doesn't get deleted by iself
def _load_modules(attr_filter=None):
import os
curdir = os.path.dirname(__file__)
imports = [os.path.splitext(fname)[0] for fname in os.listdir(curdir) if fname.endswith(".py")]
pubattrs = {}
for mod_name in imports:
mod = __import__(mod_name, globals(), locals(), ['*'], -1)
for attr in mod.__dict__:
if not attr.startswith('_') and (not attr_filter or attr_filter(mod_name, attr)):
pubattrs[attr] = getattr(mod, attr)
# Restore the global namespace to it initial state
for var in globals().copy():
if not var.startswith('_'):
del globals()[var]
# Update the global namespace with the specific items we want
globals().update(pubattrs)
# EXAMPLE: Only load classes that end with "Resource"
_load_modules(attr_filter=lambda mod, attr: True if attr.endswith("Resource") else False)
del _load_modules # Keep the namespace clean
Это просто импортирует * из всех .py файлов в каталог пакета и затем выталкивает публичные только в глобальное пространство имен. Кроме того, он позволяет фильтру, если желательны только определенные публичные атрибуты.
Ответ 4
Я использую этот простой способ:
- добавьте каталог в системный путь, затем
-
import module
или from module import function1, class1
в этом каталоге.
обратите внимание, что module
- это не что иное, как имя вашего файла *.py
без части расширения.
Вот общий пример:
import sys
sys.path.append("/path/to/folder/")
import module # in that folder
В вашем случае это может быть примерно так:
import sys
sys.path.append("subdir/")
import myclass01
# or
from myclass01 import func1, class1, class2 # .. etc
Ответ 5
from subdir.* import *
Вы не можете использовать '*' таким образом непосредственно после оператора 'from'.
Вам нужно импортировать импорт. Пожалуйста, ознакомьтесь с документацией Python по импорту и пакетам.