from sys import argv
并仅使用argv使用
argv
。但是有一个约定使用:import sys
,并通过
sys.argv
使用argv (真的)坚持下去。但是我之所以偏爱第一种方法,是因为它速度很快,因为我们仅导入所需的函数,而不是导入整个模块(该模块包含更多无用的函数,而python会浪费时间来导入它们)。请注意,我只需要argv,而sys中的所有其他功能对我来说都是无用的。所以我的问题是。第一种方法真的可以使脚本快速运行吗?哪种方法最合适?为什么?
#1 楼
导入模块不会浪费任何东西。该模块始终完全导入(导入到sys.modules
映射中),因此,无论您使用import sys
还是from sys import argv
都没有问题。 import sys
将名称sys
绑定到模块(所以sys
-> sys.modules['sys']
),而from sys import argv
绑定了另一个名称argv
,直指模块内部包含的属性(所以argv
-> sys.modules['sys'].argv
)。不管是否使用该模块中的任何其他功能,其余的sys
模块仍然存在。这两种方法之间也没有性能差异。是的,
sys.argv
必须查找两件事;它必须在全局命名空间中查找sys
(查找模块),然后查找属性argv
。是的,通过使用from sys import argv
,您可以跳过属性查找,因为您已经直接引用了该属性。但是,import
语句仍然必须执行此操作,在导入时它查找相同的属性,并且您只需要使用一次argv
。如果必须在循环中使用argv
数千次,则可能会有所不同,但在这种特定情况下,实际上并没有什么不同。那么,一个或另一个之间的选择应该基于
在一个大型模块中,我肯定会使用
import sys
;代码文档很重要,并且在大型模块中的某处使用sys.argv
可以使您所指的内容比argv
更加清晰。 argv
函数,如果您对此感到更满意,请务必使用'__main__'
:我仍然会在这里使用
main()
。所有事物都是平等的(就性能和用于编写它的字符数而言,它们都是准确的),对我来说,这更容易。如果您要完全导入其他内容,那么性能可能会发挥作用。但是仅当您多次在模块中使用特定名称(例如在关键循环中)时。但是,然后(在函数内)创建本地名称仍然会更快:
if __name__ == '__main__':
from sys import argv
main(argv)
评论
还有一种情况,您有一个带有子包或模块的包,该包暴露了顶层包中这些子包/模块之一的属性。使用from ... import允许您执行package.attribute而不是package.subpackage_or_module.attribute,如果您在包中具有逻辑或概念上的分组,但又想使包用户更方便,则这很有用。 (我相信numpy会做这样的事情。)
– JAB
2014年1月30日在16:59
在django中,您可以找到很多地方,例如django.core.management.base import BaseCommand之类的东西会更好,而其他任何东西(尤其是import django)都会导致代码无法读取。因此,尽管我喜欢这个答案,但我认为在某些库(尤其是某些框架)中,约定违反了裸导入。一如既往,根据您的判断在给定情况下的最佳选择。但是在显式方面犯了错误(换句话说,我大部分时间都同意)。
–神经网络
18年1月3日,17:24
@JAB:您仍然可以使用import ...来查找具有不同名称的软件包:import package.subpackage_or_module作为简称。从父级导入子执行的操作基本上是相同的。
–马丁·彼得斯(Martijn Pieters)
18年11月6日在14:50
因此,无论您使用import sys还是从sys import argv导入,IDLE都不会出现这种情况。只是导入模块不会导入其功能,我只能通过
–防晒
20年4月16日在12:00
@Suncatcher:请仔细阅读我的答案。您引用的句子谈论的是导入多少,而不是绑定的名称。答案中其他地方都提到了这一点。
–马丁·彼得斯(Martijn Pieters)
20年4月16日在12:38
#2 楼
有两个理由支持使用import module
而不是from module import function
。第一个是名称空间。将函数导入全局命名空间可能会导致名称冲突。
第二个与标准模块无关,但对您自己的模块很重要,尤其是在开发期间。
reload()
一个模块是可选的。考虑这个问题:from module import func
...
reload(module)
# func still points to the old code
另一方面
import module
...
reload(module)
# module.func points to the new code
速度...
我们仅导入所需的函数,而不是整个模块的导入
(包含更多无用的函数,python
会浪费时间导入它们)
无论您是导入模块还是从模块导入函数,Python都会解析整个模块。两种方式都可以导入模块。 “导入功能”无非就是将功能绑定到名称。实际上,
import module
的翻译工作比from module import func
少。评论
reload()是Python 2中的内置函数; Python 3不再是这种情况。
–André
17年9月8日在17:38
我认为循环导入依赖项也有影响吗?
– ADP
19-09-19在23:55
#3 楼
每当提高可读性时,我都会使用from import
。例如,我更喜欢(分号只是为了节省空间):from collections import defaultdict
from foomodule import FooBar, FooBaz
from twisted.internet.protocol import Factory
defaultdict(); FooBar(); FooBaz(); Factory()
而不是:
import collections
import foomodule
import twisted.internet.protocol
collections.defaultdict(); foomodule.FooBar(); foomodule.FooBaz()
twisted.internet.protocol.Factory()
后者对我来说很难读(写),因为它包含了太多冗余信息。另外,提前知道我正在使用模块的哪个部分也很有用。 br />
import sys
sys.argv; sys.stderr; sys.exit()
或者如果名称太通用以至于在名称空间之外没有意义:
import json
json.loads(foo)
from json import loads
loads(foo) # potentially confusing
评论
这是我最喜欢的答案。 “显式胜于隐式”有时会与可读性,简单性和DRY相冲突。特别是在使用像Django这样的框架时。
–神经网络
18年1月3日在17:27
#4 楼
我认为使用常规的import
可提高可读性。查看Python代码时,我喜欢看到给定的函数或类的使用来源。它使我免于滚动到模块顶部来获取该信息。对于长模块名称,我只使用
as
关键字并为其赋予短别名:import collections as col
import foomodule as foo
import twisted.internet.protocol as twip
my_dict = col.defaultdict()
foo.FooBar()
twip_fac = twip.Factory()
作为例外,在处理
from module import something
模块时,我总是使用__future__
表示法。如果您想在Python 2中将所有字符串默认设置为unicode,就无法用另一种方式进行操作,例如评论
阿们! “导入为”是一个成功的组合:-)
–paj28
2015年3月4日在17:40
#5 楼
尽管import sys
和from sys import agrv
都导入了整个sys
模块,但后者使用名称绑定,因此其余代码只能访问argv
模块。对于某些人来说,这是首选样式,因为它只会使可访问您明确声明的功能。 但是,它的确引入了潜在的名称冲突。如果您有另一个名为
argv
的模块怎么办?请注意,您还可以显式导入该函数并使用from sys import argv as sys_argv
进行重命名,q4312079q是满足显式导入且不太可能造成名称空间冲突的约定。评论
那么sys_argv:是否比sys.argv:更好呢?我知道第二种说法的含义,我不知道第一种形式的含义如果不回溯到奇怪的输入。
– msw
15年11月15日在17:54
#6 楼
我最近对自己问了这个问题。我为不同的方法定了时机。 /> json库def r():
import requests
return 'hello'
timeit r() # output: 1000000 loops, best of 3: 1.55 µs per loop
def rg():
from requests import get
return 'hello'
timeit rg() # output: 100000 loops, best of 3: 2.53 µs per loop
def bs():
import bs4
return 'hello'
timeit bs() # output: 1000000 loops, best of 3: 1.53 µs per loop
def be():
from bs4 import BeautifulSoup
return 'hello'
timeit be() # output: 100000 loops, best of 3: 2.59 µs per loop
在我看来,这有一点区别在性能上。
评论
您正在添加属性查找。要正确地将导入模块与来自模块导入名称进行比较,请将名称查找添加到导入模块的大小写中。例如。将sys.argv行添加到ar测试等。仍然存在差异,因为完成的工作略有不同,因为生成了不同的字节码并且执行了不同的代码路径。
–马丁·彼得斯(Martijn Pieters)
2015年1月8日在11:44
请注意,我在回答中直接解决了这一差异;使用import sys然后在循环中使用sys.argv数千次与使用sys import argv然后仅使用argv会有所不同。但是你没有。对于只在模块全局级别执行一次的操作,您确实应该针对可读性进行优化,而不是对时序的微观差异进行优化。
–马丁·彼得斯(Martijn Pieters)
15年1月8日,11:47
啊!而且我以为我会做某事! :)我只浏览了您的答案。好像我跳上那把枪。谦虚感到很好。
– tmthyjames
2015年1月8日在16:07
#7 楼
查看已发布的代码片段,导入整个模块并参考module.function
几乎是标准的,至少对于标准模块而言。一个例外似乎是datetime
from datetime import datetime, timedelta
,所以您可以说
datetime.now()
而不是datetime.datetime.now()
。如果您担心性能,可以总是说(例如)
argv = sys.argv
,然后执行性能关键代码,因为模块查找已完成。但是,尽管这可以与函数/方法一起使用,但是大多数IDE都会感到困惑,并且(例如)在将函数分配给变量时不会显示该函数的源链接/签名。
#8 楼
我只想补充一点,如果您做类似from math import sin
(或任何其他内置库,例如
sys
或posix
),则sin
将包含在文档中为您的模块(例如,当您执行>>> help(mymodule)
或$ pydoc3 mymodule
时。要避免这种情况,请使用以下命令导入:代码并包含在Python中。argparse
,os
和io
不是内置包
评论
另请参见stackoverflow.com/q/710551/321973相关文章-Python中…import…语法背后的推理