我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。
基本上,我希望任何人都能分享他们的经验,其他开发者有什么偏好,以及避免任何陷阱的最佳方法是什么?
我试图找到一个全面的指南,是否最好使用导入模块或从模块导入。我刚刚开始学习Python,我正试图从最佳实践开始。
基本上,我希望任何人都能分享他们的经验,其他开发者有什么偏好,以及避免任何陷阱的最佳方法是什么?
当前回答
我正在回答一个类似的问题,但在我发布之前,发帖者删除了它。这里有一个例子来说明这些区别。
Python库可以有一个或多个文件(模块)。为例子,
package1
|-- __init__.py
or
package2
|-- __init__.py
|-- module1.py
|-- module2.py
我们可以在任何基于设计需求的文件中定义python函数或类。
让我们来定义
在mylibrary1下的__init__.py中的Func1 () mylibrary2下的module2.py中的Foo()。
我们可以使用这些方法之一访问func1()
import package1
package1.func1()
or
import package1 as my
my.func1()
or
from package1 import func1
func1()
or
from package1 import *
func1()
我们可以使用以下方法之一来访问foo():
import package2.module2
package2.module2.foo()
or
import package2.module2 as mod2
mod2.foo()
or
from package2 import module2
module2.foo()
or
from package2 import module2 as mod2
mod2.foo()
or
from package2.module2 import *
foo()
其他回答
有一些内置模块主要包含裸函数(base64, math, os, shutil, sys, time,…),将这些裸函数绑定到某个名称空间绝对是一个很好的实践,从而提高代码的可读性。想想看,如果没有命名空间,要理解这些函数的含义是多么困难:
copysign(foo, bar)
monotonic()
copystat(foo, bar)
当它们被绑定到某个模块时:
math.copysign(foo, bar)
time.monotonic()
shutil.copystat(foo, bar)
有时你甚至需要命名空间来避免不同模块之间的冲突(json. xml)。Load vs. pickle.load) 另一方面,有些模块包含大部分类(configparser, datetime, tempfile, zipfile,…),其中许多模块的类名不言自明:
configparser.RawConfigParser()
datetime.DateTime()
email.message.EmailMessage()
tempfile.NamedTemporaryFile()
zipfile.ZipFile()
因此,在代码中使用这些类和额外的模块名称空间是增加了一些新信息还是只是延长了代码,可能会有争论。
我发现的一个显著区别是,令人惊讶的是,没有人讨论过使用纯导入,你可以从导入的模块中访问私有变量和私有函数,这是from-import语句无法实现的。
图像中的代码:
setting.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")
plain_importer.py
import settings
print (settings._private_variable)
print (settings.public_variable)
settings.public_function()
settings._private_function()
# Prints:
# 141
# 42
# I'm a public function! yay!
# Ain't nobody accessing me from another module...usually
from_importer.py
from settings import *
#print (_private_variable) #doesn't work
print (public_variable)
public_function()
#_private_function() #doesn't work
@ahfx已经提到了这些导入的一个关键方面,即加载模块过程的内部。如果你的系统需要使用循环导入(例如,你想在一些流行的http框架中使用依赖注入),就会弹出这个窗口。在这种情况下,from {module} import {function}对于加载过程如何进行的要求显得更加激进。让我们举个例子:
#m1.py:
print('--start-m1--')
from m2 import * # form does not matter; just need to force import of m2
print('--mid-m1--')
def do1(x):
print(x)
print('--end-m1--')
进口
#m2.py
print('--start-m2--')
# from m1 import * # A
# from m1 import do1 # B
# import m1 # C
# D -- no import of "do1" at all
print('--mid-m2--')
def do2(x):
m1.do1(x)
print('--end-m2--')
通过运行
#main.py:
from m1 import do1
do1('ok')
在m2.py (A,B,C,D)中的所有导入选项中,from {module} import {function}是唯一会导致加载过程崩溃的选项,导致臭名昭著的(CPython 3.10.6)
ImportError: cannot import name 'do1' from partially initialized module 'm1'
(most likely due to a circular import)
虽然我不能说为什么会发生这种情况,但似乎从……进口…语句对有问题的模块已经处于初始化过程的“多远”提出了更严格的要求。
支持这两种方法是有原因的:有时一种比另一种更合适。
导入模块:当你从模块中使用很多位的时候很好。缺点是需要用模块名限定每个引用。 从模块导入…:导入的项目可以直接使用,不需要模块名前缀。缺点是必须列出所使用的每一个东西,并且在代码中不清楚某些东西是从哪里来的。
使用哪种方法取决于哪种方法使代码清晰易读,并且与个人喜好有很大关系。我通常倾向于导入模块,因为在代码中,对象或函数的来源非常清楚。我使用from module import…当我在代码中经常使用一些对象/函数时。
因为我也是初学者,我将尝试用一种简单的方式解释这一点: 在Python中,我们有三种类型的import语句,分别是:
1. 一般进口:
import math
这种类型的导入是我个人最喜欢的,这种导入技术的唯一缺点是,如果你需要使用任何模块的函数,你必须使用以下语法:
math.sqrt(4)
当然,它增加了输入工作,但作为初学者,它将帮助您跟踪与之相关的模块和函数(一个好的文本编辑器将大大减少输入工作,推荐使用)。
输入工作可以通过使用import语句进一步减少:
import math as m
现在,您可以使用m.s rt()而不是math.sqrt()。
2. 功能导入:
from math import sqrt
如果您的代码只需要访问模块中的单个或少数函数,则这种类型的导入最适合,但如果要使用模块中的任何新项,则必须更新import语句。
3.普遍的进口:
from math import *
虽然它大大减少了输入工作量,但不推荐,因为它将用模块中的各种函数填充代码,并且它们的名称可能与用户定义函数的名称冲突。 例子:
如果你有一个自己命名为sqrt的函数,并且你导入了math,你的函数是安全的:这是你的sqrt,这是math.sqrt。但是,如果从math import *执行,则会遇到一个问题:即,两个不同的函数具有完全相同的名称。来源:“