我一直在使用这种方法:

from sys import argv


并仅使用argv使用argv。但是有一个约定使用:

import sys


,并通过sys.argv使用argv (真的)坚持下去。但是我之所以偏爱第一种方法,是因为它速度很快,因为我们仅导入所需的函数,而不是导入整个模块(该模块包含更多无用的函数,而python会浪费时间来导入它们)。请注意,我只需要argv,而sys中的所有其他功能对我来说都是无用的。

所以我的问题是。第一种方法真的可以使脚本快速运行吗?哪种方法最合适?为什么?

评论

另请参见stackoverflow.com/q/710551/321973

相关文章-Python中…import…语法背后的推理

#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都不会出现这种情况。只是导入模块不会导入其功能,我只能通过名称在IDLE shell中调用它

–防晒
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 sysfrom 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


(或任何其他内置库,例如sysposix),则sin将包含在文档中为您的模块(例如,当您执行>>> help(mymodule)$ pydoc3 mymodule时。要避免这种情况,请使用以下命令导入:代码并包含在Python中。argparseosio不是内置包