这是我正在使用的结构:
directory/
script.py
subdir/
__init__.py
myclass01.py
myclass02.py
Run Code Online (Sandbox Code Playgroud)
我想要做的就是在script.py中定义的类进口myclass01.py和myclass02.py.如果我做:
from subdir.myclass01 import *
Run Code Online (Sandbox Code Playgroud)
它适用于定义的类myclass01.py.但是使用这个解决方案,如果在不同的文件中定义了许多类,subdir并且我想要导入所有这些类,我必须为每个文件键入一行.必须有一个捷径.我试过了:
from subdir.* import *
Run Code Online (Sandbox Code Playgroud)
但它没有成功.
编辑:这是文件的内容:
这是__init__.py(使用__all__Apalala建议):
__all__ = ['MyClass01','MyClass02']
Run Code Online (Sandbox Code Playgroud)
这是myclass01.py:
class MyClass01:
def printsomething():
print 'hey'
Run Code Online (Sandbox Code Playgroud)
这是myclass02.py:
class MyClass02:
def printsomething():
print 'sup'
Run Code Online (Sandbox Code Playgroud)
这是script.py:
from subdir import *
MyClass01().printsomething()
MyClass02().printsomething()
Run Code Online (Sandbox Code Playgroud)
这是我尝试运行时获得的回溯script.py:
File "script.py", line 1, in <module>
from subdir import *
AttributeError: 'module' object has no attribute 'MyClass01'
Run Code Online (Sandbox Code Playgroud)
mar*_*eau 12
虽然在那里使用的名称与您的问题的目录结构中显示的名称不同,但您可以使用我对题为命名空间和类的问题的答案.在__init__.py那里显示本来还允许usepackage.py脚本已经(被写成这样package映射到subdir你的问题,并Class1以myclass01等):
from package import *
print Class1
print Class2
print Class3
Run Code Online (Sandbox Code Playgroud)
修订(更新):
糟糕,抱歉,我的其他答案中的代码并不能完全按照您的意愿行事 - 它只会自动导入任何包子模块的名称.要使它还从每个子模块导入命名属性,还需要几行代码.这是包__init__.py文件的修改版本(也适用于Python 3.4.1):
def _import_package_files():
""" Dynamically import all the public attributes of the python modules in this
file's 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__
Run Code Online (Sandbox Code Playgroud)
或者,您可以将上面的内容放在一个单独的.py模块文件中,并在包目录中使用它,__init__.py如下所示:
if __name__ != '__main__':
from ._import_package_files import * # defines __all__
__all__.remove('__all__') # prevent export (optional)
Run Code Online (Sandbox Code Playgroud)
无论你命名文件是什么,它应该是以_下划线字符开头的东西,所以它不会import递归地尝试自己.
您最好的选择,虽然可能不是最好的样式,但是将所有内容导入到包的命名空间中:
# this is subdir/__init__.py
from myclass01 import *
from myclass02 import *
from myclass03 import *
Run Code Online (Sandbox Code Playgroud)
然后,在其他模块中,您可以直接从包中导入所需内容:
from subdir import Class1
Run Code Online (Sandbox Code Playgroud)
我知道自从这个问题得到解答以来已经有几个月了,但是我一直在寻找同样的事情并且浏览了这个页面.我对所选择的答案并不是很满意,所以我最终编写了自己的解决方案,并认为我会分享它.这是我想出的:
# 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's 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
Run Code Online (Sandbox Code Playgroud)
这只是从包目录中的所有.py文件中导入*,然后只将公共文件拉入全局命名空间.此外,如果只需要某些公共属性,它允许过滤器.