2019年10月31日 / 417次阅读 / Last Modified 2021年4月22日
语法
在python中导入模块,一般就是直接import module。另一种方式是from module import *,这种方式将导入模块中所有的非下划线(_)开始的对象,这种全部导入的方式,有人说容易污染namespace,不过,还是有方法可以控制可导入对象的。
一个值得注意的细节:import只能跟module或package,而from ... import可以跟函数,类,变量等对象!
直接import一个模块,那么这个模块所有的对象,都可以通过模块名来访问,因此不管名称有无下划线,统统都可以访问。
$ cat all.py
a = 1
b = 2
_c = 3
__d = 4
def aa(): pass
def bb(): pass
def _cc(): pass
def __dd(): pass
class aaa(): pass
class bbb(): pass
class _ccc(): pass
class __ddd(): pass
all.py这个文件中,有一些带下划线的对象,我们在python解释器中直接import all看一下效果:
>>> import all
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'all']
>>> dir(all)
['__builtins__', '__cached__', '__d', '__dd', '__ddd', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_c', '_cc', '_ccc', 'a', 'aa', 'aaa', 'b', 'bb', 'bbb']
all中所有的对象,都要通过all这个模块名来访问,因此直接调用dir()函数,只能看到模块all,要使用dir(all),才能看到所有的对象。可以发现,不管是一个下划线,还是两个下划线,所有的对象都可以通过all模块来访问。
>>> from all import *
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'aa', 'aaa', 'b', 'bb', 'bbb']
所有带下划线的对象,都没有导入进来。from module import * 不会导入带下划线的对象。
使用from的另一个细节是:对象直接导入到上层namespace中,对象直接通过自己的名字就可以访问,这时要注意名字冲突!
在使用from的情况下,有两种方式可以控制具体导入什么对象。
列出具体的对象名
>>> from all import a,bb,_cc
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_cc', 'a', 'bb']
列出具体的对象名,就可以在from的时候,导入带下划线的对象。
使用__all__属性
修改一下all.py文件,增加一个__all__属性:
$ cat all.py
__all__ = ['a','b','_cc','__ddd']
a = 1
b = 2
_c = 3
__d = 4
def aa(): pass
def bb(): pass
def _cc(): pass
def __dd(): pass
class aaa(): pass
class bbb(): pass
class _ccc(): pass
class __ddd(): pass
注意__all__这个list中的元素,要带引号。
这个时候,再使用from加*,就只能import __all__这个list中的对象,起到控制的作用:
>>> from all import *
>>> dir()
['__annotations__', '__builtins__', '__ddd', '__doc__', '__loader__', '__name__', '__package__', '__spec__', '_cc', 'a', 'b']
这种用法,也可以导入带下划线的对象。
如果是写一个模块给别人用的,最好是加上__all__这个属性,控制一下比较好。自己写代码,采用列出对象名的显式的方式,会比较清晰。一般不建议使用from module import *这个方式。
-- EOF --
本文链接:https://www.pynote.net/archives/1417
《from module import * 中的细节》有3条留言
©Copyright 麦新杰 Since 2019 Python笔记
用star import存在一个问题:再用flake8做lint的时候,undefined name就无法检查了,而这个undefined name对于像python这样解释执行的语言来说,是个很重要的潜在风险点。因为undefined name只有在执行到那一行代码的时候,才知道是否正确,测试就要求100%分支覆盖,这在很多时候是比较困难和耗时的。 [ ]
star import [ ]
如果__all__中带单引号的对象没有被定义,from引入的时候,会抛出AttributeError。直接import时,无视__all__。 [ ]