为什么可以';t Python';像C';包括什么?

为什么可以';t Python';像C';包括什么?,python,c,import,Python,C,Import,我已经花了大约一年的时间试图理解Python导入,我几乎放弃了用Python编程,因为它看起来太模糊了。我来自C语言背景,我假设import的工作方式类似于#include,但是如果我尝试导入一些东西,我总是会出错 如果我有两个这样的文件: foo.py: a = 1 bar.py: import foo print foo.a input() 为什么我需要引用模块名称?为什么不能够编写导入foo,打印一个?这种混乱的意义是什么?为什么不运行代码并为您定义一些东西,就像您在一个大文件中编写它

我已经花了大约一年的时间试图理解Python导入,我几乎放弃了用Python编程,因为它看起来太模糊了。我来自C语言背景,我假设
import
的工作方式类似于
#include
,但是如果我尝试导入一些东西,我总是会出错

如果我有两个这样的文件:

foo.py:

a = 1
bar.py:

import foo
print foo.a
input()

为什么我需要引用模块名称?为什么不能够编写
导入foo
打印一个
?这种混乱的意义是什么?为什么不运行代码并为您定义一些东西,就像您在一个大文件中编写它一样?为什么它不能像C的#include指令那样基本上复制和粘贴代码?我在C中没有导入问题。

要执行您想要的操作,您可以使用(不推荐,请进一步阅读以获取解释):

这将把所有内容导入到您当前的名称空间,您将能够调用
print a

然而,这种方法的问题如下。考虑当你有两个模块时,<代码>模块E/<代码>和<代码>模块B ,每个都有一个名为<代码> GETSOMACEDIONE()/<代码>的函数。 当您这样做时:

from moduleA import *
from moduleB import *
您有一个名称空间解析问题*,因为您实际使用
GetSomeValue()
moduleA.GetSomeValue()
moduleB.GetSomeValue()
调用什么函数

除此之外,您还可以使用导入为功能:

from moduleA import GetSomeValue as AGetSomeValue
from moduleB import GetSomeValue as BGetSomeValue

此方法手动解决冲突

我相信你能从这些例子中体会到明确引用的必要性


*Python有其名称空间解析机制,这只是为了解释的目的而进行的简化。

当您执行
导入foo
时,将在名为
foo
的当前名称空间内创建一个新的
模块

所以,使用foo中的任何东西;您必须通过模块对其进行寻址


但是,如果您使用from
from foo import something
,则不必使用预先添加模块名称,因为它将从模块加载
something
,并为其指定名称
something
。(不是推荐的做法)

有几个很好的理由。该模块为其中的对象提供了一种名称空间,它允许您使用简单的名称,而不必担心冲突——来自C语言背景,您肯定看到过函数名冗长难看的库,以避免与其他库发生冲突

此外,模块本身也是对象。当在python程序中的多个位置导入模块时,每个模块实际上都会获得相同的引用。这样,更改
foo.a
会为每个人更改它,而不仅仅是本地模块。这与C语言不同,C语言中包含一个头基本上是一个复制+粘贴到源文件中的操作(显然,您仍然可以共享变量,但机制有点不同)

如前所述,您可以说来自foo import*
,或者更好地说来自foo import a的
,但要理解底层行为实际上是不同的,因为您正在使用
a
并将其绑定到本地模块

如果您经常使用某个模块,您可以始终使用
from
语法直接导入该模块,或者您可以将该模块重命名为较短的模块,例如

import itertools as it

假设您的模块中有一个函数,该函数从列表中选择某个对象:

def choice(somelist):
    ...
现在进一步想象一下,无论是在该函数中还是在模块的其他地方,您都在使用
random
库中的
randint

a = randint(1, x)
所以我们

import random
您的建议是,这就是现在由
从random import*
访问的功能,这意味着我们现在有两个不同的函数叫做choice,因为
random
也包括一个。只有一个是可访问的,但您对
choice()

这就是为什么进口任何东西都是不好的做法;要么导入所需内容:

from random import randint
...
a = randint(1, x)
或整个模块:

import random
...
a = random.randint(1, x)
这有两个好处:

  • 将名称重叠的风险降至最低(现在和将来添加到导入的模块中);及
  • 当其他人阅读您的代码时,他们可以很容易地看到外部函数的来源
  • 导入导入库
    #就像C的#include,你总是用include(,u_name_uu)来称呼它
    def包括(文件、模块名称):
    spec=importlib.util.spec\u from\u file\u位置(模块名称,文件)
    mod=importlib.util.module\u from\u spec(spec)
    #规格加载程序执行模块(mod)
    o=规格加载器。获取代码(模块名称)
    exec(o,globals())
    
    例如:

    文件a.py####
    a=1
    ####文件b.py####
    b=2
    如果名称=“\uuuuu main\uuuuuuuu”:
    打印(“嗨,我是b.py”)
    ####文件main.py####
    #假设您在范围中有“include”
    包括(“a.py”、\uuuuu名称\uuuuuuu)
    印刷品(a)
    包括(“b.py”、\uuuuu名称\uuuuuuu)
    印刷品(b)
    
    输出将是:

    1
    Hi, this is b.py
    2
    

    这不是一个坏习惯吗?@turbulencetoo:或者你可以直接导入名字<代码>来自foo import a
    @DylanLaCoursiere:您错误地认为您是所有代码的唯一作者。但是不同的程序员在不同的模块上工作,许多第三方模块可以在您的应用程序中使用。您无法确保它们都具有唯一的函数名和变量名。这将是愚蠢的,如果你仔细考虑的话,名称空间确实是最好的解决方案。@DylanLaCoursiere:我认为你不理解这个问题。看看下面的例子。一个人正在开发TCP客户端库。它显然会有Connect()方法,因为TCP客户机就是这样做的。与此同时,在世界的另一端,有人正在开发HTTP客户端。很明显,他将为它实现连接功能。几天后,有人决定创建一个applic
    import random
    ...
    a = random.randint(1, x)
    
    1
    Hi, this is b.py
    2