Python 模块导入
请注意,通常不赞成*从模块或包中导入的做法,因为它通常会导致代码可读性差。但是,可以使用它来保存交互式会话中的输入。
import fibo # 隐式相对导入
from fibo import fibo1, fibo2 # 绝对路径导入
import fibo as fib # 重命名
from fibo import fib as fibonacci
笔记
出于效率原因,每个模块在每个解释器会话中仅导入一次。因此,如果您更改您的模块,您必须重新启动解释器——或者,如果它只是您想要交互式测试的一个模块,请使用
importlib.reload()
,例如.
import importlib;
importlib.reload(modulename)
from package import item
,item可以是package的子module,也可以是子package, 还可以是其他各种定义在这个包里面的变量、类和函数。
import item.subitem.subsubitem
,这种语法则要求最后一层item必须是子package,或者子module,不能是item中定义的变量、类或者函数。如果最后一层是一个变量、类或者函数,则在编译改文件的时候会报错ModuleNotFoundError: No module named 'xxx'; 'xxx' is not a package
from <module> import *
包外的可见效是通过在包里面的__init.py__里面设置__all__来控制包内的对象和方法等对包外的可见性,如:如果设置了__all__,如果这个包内的类或方法不在__all__里面,外面的包就不能正常使用这些方法和类。如果没有设置__all__,那么外面可以通过包内的约定来显示可见性。python通过private对应两个下划线__,protected对应一个下划线_,public 对应没有下划线,来约定类似于java的可见性控制。
__all__作用是是限制
from <module> import *
中
import
的包名。需要注意的是
__all__
只影响到了
from <module> import *
这种导入方式,对于
from <module> import <member>
导入方式并没有影响,仍然可以从外部导入。
all__如果在module文件中,则限制的是module中变量、类和函数的可见性,所以这种情况下__all__变量的元素都是变量名、类名和函数名;如果是在__init.py中,则设置的是该package下的module的可见性,这种情况下,__all__变量的元素都是module名。
├──__init__.py
├── package1
│ ├── __init__.py
│ ├── foo.py
│ ├── foo1.py
│ └── foo2.py
└──example.py
每个文件的内容分别如下
package1.init.py,在__all__变量中只定义了"foo1"和"foo2"两个module,当使用
from package1 import *
导入package1下的module时,只会导入foo1和foo2两个module
__all__ = ["foo1", "foo2"]
package1.foo.py
ccc = 5
bar = 10
def baz(): return 'baz'
package1.foo1.py
aaa = 123
str = "aaa"
package1.foo2.py
bbb = 456
example.py
from package1 import *
if __name__ == "__main__":
print(foo1.aaa)
print(foo2.bbb)
print(foo.ccc) # 报错,NameError: name 'foo' is not defined
因为
__all__
from <module> import *
from <module> import <member>
导入方式并没有影响,仍然可以从外部导入。所以我们可以使用
from package1 import foo
来导入foo这个module。
example.py改成如下,即不会报错。
from package1 import *
from package1 import foo
if __name__ == "__main__":
print(foo1.aaa)
print(foo2.bbb)
print(foo.ccc) # 不报错
相对导入
from . import echo # 表示从当前文件所在目录导入echo这个module
from .. import formats # 表示从当前文件所在目录的上层目录导入formats这个package或者moudle
from ..filters import equalizer # 表示从当前文件所在目录的上层目录的filters这个子package或者子module中导入equalizer
相对导入基于当前模块的名称。由于主模块的名称始终为
"__main__"
,因此用作 Python 应用程序主模块的模块必须始终使用绝对导入。主模块所在文件夹不会被视作package,因此除了主模块外,与主模块处在同个文件夹的模块(也就是同级的模块)也必须使用绝对导入。
关于相对导入,建议阅读,能让你对相对导入有一个深刻的认识,再也不用怕相对导入引起的编译失败了。
将模块作为脚本执行
fibo.py
# Fibonacci numbers module
def fib(n): # write Fibonacci series up to n
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
def fib2(n): # return Fibonacci series up to n
result = []
a, b = 0, 1
while a < n:
result.append(a)
a, b = b, a+b
return result
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
脚本中的__main__="__name"下的代码仅在模块作为“主”文件执行时才运行:
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
如果module是作为导入的模块,则不会执行该模块的__main__代码:
>>>import fibo
>>>
这通常用于为模块提供方便的用户界面,或用于测试目的(将模块作为脚本执行测试套件运行)。
模块搜索路径
当import一个module时,比如spam,解释器首先搜索具有该名称的内置模块。如果未找到,它将从
sys.path
这个目录列表中搜索spam.py这个文件。
sys.path
初始状态一般由三部分组成:python正在执行的脚本的目录,PYTHONPATH路径,包的默认安装路径。
在支持符号链接的文件系统上,包含输入脚本的目录是在符号链接之后计算的。换句话说,包含符号链接的目录不会添加到模块搜索路径中。
初始化后,Python 程序可以修改
sys.path
. 包含正在运行的脚本的目录位于搜索路径的开头,在标准库路径之前。这意味着将加载该目录中的脚本而不是库目录中的同名模块。最好不要有和内置模块相同的名字的module, 因为当前文件夹的module在被搜索时会被优先搜索。
“已编译”的 Python 文件
我们在运行python文件后经常能看到被运行的文件的目录下增加了一个__pycache__文件夹,里面多了很多.pyc文件。以前可能不太清楚这些.pyc文件是什么,重要不重要,能不能随便删除以及这些文件是怎么产生的等等疑问。现在看完这个章节就完全了解了__pycache__这个神秘的文件夹。
为了加速模块载入,Python会把每个模块的编译后版本存在在 pycache 目录中,每个module的命名格式为 moduleName.cpython-version.pyc ,其中名称中的version是python的版本号。例如,在CPython版本3.3中,spam.py的编译版本将被缓存为 pycache/spam.cpython-33.pyc。因为带上了版本号,所以不同版本的python的已编译模块可以共存。
Python根据编译版本检查源的修改日期,以查看它是否已过期并判断需要重新编译。这是一个完全自动化的过程。
Python在两种情况下不会检查缓存。首先,对于从命令行直接载入的模块,它从来都是重新编译并且不存储编译结果;其次,如果没有源模块,它不会检查缓存。为了支持无源文件(仅编译)发行版本, 编译模块必须是在源目录下,并且绝对不能有源模块。
- 程序从
文件中读取时的运行速度并不比从文件中读取时快.pyc
;唯一比.py
文件更快的是它们的加载速度。.pyc
dir()函数
dir()函数会找到并列出一个module定义的所有函数、变量和类。
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys) ['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
'__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
'__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
'_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
'_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
'warnoptions']
如果dir()函数的参数为空,会默认列出当前已经定义的所有变量、函数名和类。
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
dir()
默认不列出内置函数和变量的名称。所有内置函数的名称和变量都定义在标准模块
builtins
中。
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
可以看到,很多我们过去使用过的函数其实都是内置函数,包括len, list, int, print,pow等等。
参考: 6.模块