Python中使用语句导入模块或包的机制研究
作者:Shahriar Tajbakhsh 发布时间:2023-02-21 15:06:40
这篇文章讨论了Python的from <module> import *和from <package> import *,它们怎么执行以及为什么使用这种语法(也许)是一个坏主意。
从一个模块导入全部
from <module> import * means意味着“我希望能访问<module>中我有权限访问的全部名称”。例如以下代码something.py:
# something.py
public_variable = 42
_private_variable = 141
def public_function():
print("I'm a public function! yay!")
def _private_function():
print("Ain't nobody accessing me from another module...usually")
class PublicClass(object):
pass
class _WeirdClass(object):
pass
在Python解释器中,我们可以执行from something import *,然后看到如下的内容:
>>> from something import *
>>> public_variable
42
>>> _private_variable
...
NameError: name '_private_variable' is not defined
>>> public_function()
"I'm a public function! yay!"
>>> _private_function()
...
NameError: name '_private_function' is not defined
>>> c = PublicClass()
>>> c
<something.PublicClass object at ...>
>>> c = _WeirdClass()
...
NameError: name '_WeirdClass' is not defined
from something import *从something中导入了除了以_开头名称外的其他所有名称,按照规范,_开始的名称是私有的所以未被导入。
嗯,不是特别糟!还有什么?
上面没提到__all__是什么。__all__是一个字符串列表,指定了当from <module> import *被使用时,模块(或者如后文会提到的包)中的哪些符号会被导出。如果我们不定义__all__(我们在上面的something.py就没定义),import *默认的导入方式是导入除了下划线(_)开头的所有名称。再说一次,编程惯例上下划线表示一个符号是私有的,不导入是合理的。让我们来看看在something.py中定义我们自己的__all__会发生什么。
# something.py
__all__ = ['_private_variable', 'PublicClass']
# The rest is the same as before
public_variable = 42
_private_variable = 141
def public_function():
print("I'm a public function! yay!")
def _private_function():
print("Ain't nobody accessing me from another module...usually")
class PublicClass(object):
pass
class _WeirdClass(object):
pass
现在,我们期望from something import *只会导入_private_variable和PublicClass:
>>> from something import *
>>> public_variable
42
>>> _private_variable
...
NameError: name '_private_variable' is not defined
>>> public_function()
"I'm a public function! yay!"
>>> _private_function()
...
NameError: name '_private_function' is not defined
>>> c = PublicClass()
>>> c
<something.PublicClass object at ...>
>>> c = _WeirdClass()
...
NameError: name '_WeirdClass' is not defined
包是怎样的呢?
当从一个包中导入全部时,__all__的做法和模块基本一样,不过它处理的是包中的模块(而不是把模块中的名都导入)。所以当我们使用from <package> import *.时__all__说明了所有需要被导入当前命名空间的模块。
不同之处在于,如果你在一个包的__init__.py里面没有声明__all__,from <package> import *语句不会导入任何东西(这个说法也不全对,正确的说法在此)
但是,这有什么不好?
继续读之前,在你的Python解释器中,执行import this,再读一遍Python之禅(在你孩子每晚睡前也要读给他们)。
明确比含糊要好。
from <module> import * 是不明确的。它没告诉我们我们正在导入什么或者我们把什么带入当前命名空间了。更好的做法是显式地导入我们需要的全部名称。这种方式下,读者(非常可能是未来的你自己)就不会困惑于你代码中使用的一个变量/方法/类/其他东西是哪儿来的,这也告诉了我们下一点:
可读性很重要
即使你需要导入很多东西,一个一个显式地导入也更清楚。使用PEP 328:
from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
LEFT, DISABLED, NORMAL, RIDGE, END)
你现在就能明确知道你的命名空间里有什么,使用ctrl+f能很快地告诉你它们是哪儿来的。
同时,你还总是要承担模块/包作者更改list内容(加/减东西)的风险。也就是下面两者之一:
作者从__all__里删除了一个字符串。如果你的代码使用了那个名字,你的代码就会报出NameError的错误,并且很难发现为什么。
作者在__all__里加入了很多东西。你也许不需要这些增加的内容,所以你只是让这些你不关心的东西占满了你的命名空间。他们甚至在你不注意的时候会替代其他同名内容。
当然,有时候从模块或者包中导入全部内容是有用的。不过,这么做之前三思。从我的经验来看,这么做通常只是因为懒。


猜你喜欢
- 修改数据库字符集:ALTER DATABASE db_name DEFAULT CHARACTER SET character_name [
- 在定义图结构之前不用加入gpu:0,只有在session中计算之前在加入,否则的话会提示不能使用gpu保存模型等问题。 with  
- 最近在看红楼梦,看的诗词多了,时不时的也想来一句...这几天刚看看到了underscore.js的防抖和节流的部分,正好又去复习了这部分内容
- 问题你想使用一个装饰器去包装函数,但是希望返回一个可调用的实例。 你需要让你的装饰器可以同时工作在类定义的内部和外部。解决方案为了将装饰器定
- 喜欢用 Python 做项目的小伙伴不免会遇到这种情况:做图表时,用哪种好看又实用的可视化工具包呢?之前文章里出现过漂亮的图表时,也总有读者
- function chinese2unicode(Str) &nbs
- WSGI协议首先弄清下面几个概念:WSGI:全称是Web Server Gateway Interface,WSGI不是服务器,python
- 啥是JWTJWT全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端
- 最近有同学询问如何利用Python处理xml文件,特此整理一个比较简洁的操作手册,供大家参阅。首先准备一个xml文件,xml中的内容如下所示
- SQL Server数据库查询速度慢的原因有很多,常见的有以下几种:1、没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)
- 业务场景因为项目刚上线,目前暂不打算引入其他中间件,所以打算通过 mysql 来实现分布式读写锁;而该业务场景也满足分布式读写锁的场景,抽象
- 一、re是什么?正则表达式是一个特殊的字符序列,能方便的检查一个字符串是否与某种模式匹配。re模块使得python拥有全部的正则表达式功能。
- springboot配置文件抽离,便于服务器读取对应配置文件,避免项目频繁更改配置文件,影响项目的调试与发布1.创建统一配置中心项目coni
- 本文实例讲述了python使用datetime模块计算各种时间间隔的方法。分享给大家供大家参考。具体分析如下:python中通过dateti
- Composer的基本使用在项目中使用composer.json在项目中使用composer,你需要有一个composer.json文件,此
- 本文实例讲述了mysql共享锁与排他锁用法。分享给大家供大家参考,具体如下:mysql锁机制分为表级锁和行级锁,本文就和大家分享一下我对my
- 一、激活函数1.Sigmoid函数函数图像以及表达式如下:通过该函数,可以将输入的负无穷到正无穷的输入压缩到0-1之间。在x=0的时候,输出
- 废话不多说,直接上代码<?php // 暂不支持断点续传 // $url = 'http://www.
- 在JavaScript中,我们应该尽可能的用局部变量来代替全局变量,这句话所有人都知道,可是这句话是谁先说的?为什么要这么做?有什么根据么?
- 做WEB前台开发也有两年多,在开发中经常要涉及到DOM编程,我想大家也跟我一样,经常要处理各种DOM编程的操作,今天我就拿一个lightbo