当前位置: 首页 > 面试题库 >

Python模块初始化顺序?

陈刚洁
2023-03-14
问题内容

我是来自C 背景的Python新手。虽然我知道用我以前的C 知识来尝试找到匹配的概念并不是Pythonic,但我认为这个问题仍然是一个普遍的问题:

在C 中,由于C

无法确定哪个全局/静态变量将首先在编译单元中初始化,因此存在一个众所周知的全局/静态变量初始化顺序失败的问题,因此,全局/静态变量取决于不同编译中的另一个变量单元可能比其依赖项对应的对象早初始化,并且当依赖项开始使用依赖项对象提供的服务时,我们将具有未定义的行为。在这里,我不想深入探讨C
++如何解决此问题。:)

在Python世界中,我的确看到了全局变量的使用,甚至跨不同的.py文件使用,而且我看到的一个典型用法是:在一个.py文件中初始化一个全局对象,在其他.py文件中初始化该代码,不用担心。开始使用全局对象,假设它必须已经在其他地方初始化过,由于我上面指定的问题,在C
++下我绝对不能接受它。

我不确定上述用例是否在Python(Pythonic)中是常见的做法,Python一般如何解决这种全局变量初始化顺序问题?

非常感谢你!


问题答案:

在C 中,存在一个众所周知的问题,称为全局/静态变量初始化顺序失败,原因是C 无法确定哪个全局/静态变量将首先在编译单元中初始化,

我认为该声明突出了Python和C 之间的关键区别:在Python中,没有诸如不同的编译单元之类的东西。我的意思是,在C

(如您所知)中,两个不同的源文件可能完全彼此独立地进行编译,因此,如果您比较文件A中的一行和文件B中的一行,就没什么好说的了您将被放置在程序的第一位。这有点像具有多个线程的情况:您无法说出线程1中的特定语句是在线程2中的特定语句之前还是之后执行。您可以说C
++程序是并行编译的。

相反,在Python中,执行从一个文件的顶部开始,并以明确定义的顺序在文件中的每个语句中进行,然后在导入它们的位置分支到其他文件。实际上,您几乎可以将import指令视为#include,并可以通过这种方式确定程序中所有源文件中所有代码行的执行顺序。(好吧,这要复杂得多,因为模块只有在第一次导入时才真正执行,并且由于其他原因。)如果C
++程序是并行编译的,则Python程序将被串行解释。

您的问题还涉及Python中模块的更深层含义。Python模块-包含在单个.py文件中的所有内容-
是实际对象。单个源文件中在“全局”范围内声明的所有内容实际上都是该模块对象的属性。Python中没有真正的全局范围。(Python程序员经常说“全局”,实际上global在该语言中有一个关键字,但它实际上始终是指当前模块的顶层。)我可以看到,要习惯于使用一个奇怪的概念从C
背景开始。来自Java的使我适应了一些习惯,在这方面,Java与Python相比,与C 更加相似。(Java中也没有全局范围)

我将提到在Python中使用变量是完全正常的,而不知道是否已初始化/定义变量。好吧,也许不正常,但在适当情况下至少可以接受。在Python中,尝试使用未定义的变量会引发NameError;
您不会像在C或C ++中那样获得任意行为,因此您可以轻松地处理这种情况。您可能会看到以下模式:

try:
    duck.quack()
except NameError:
    pass

如果duck不存在,则不执行任何操作。其实,您通常会看到的是

try:
    duck.quack()
except AttributeError:
    pass

如果duck没有名为的方法,则不执行任何操作quack。(这AttributeError是您尝试访问对象的属性时遇到的错误,但是该对象没有该名称的任何属性。)这就是通过Python中的类型检查所通过的:我们认为如果需要的话鸭子要做的是嘎嘎,我们可以要求鸭子嘎嘎,如果是,我们不在乎它是否
真的 是鸭子。(这被称为鸭子打字;-)



 类似资料:
  • 我有一个Java Spring Boot应用程序,在我的Maven pom.xml中将Flyway配置为依赖项(我有一个父pom和一个项目pom...Flyway是在我的项目pom中定义的)。 application.properties中只有几个条目: 我可以运行一个maven任务来让Flyway运行来创建/更新我的数据库,然后针对该数据库运行我的应用程序,但是我很难通过运行我的应用程序(这在p

  • 问题内容: 正如某些消息来源所说,Java实例初始化块在创建实例时或在构造函数之前立即执行。但是想象一下这种情况: 输出是(如预期的那样): 所以我的问题是-实例初始化块的正确定义是什么,因为它显然没有在构造函数之前执行,因为输出应该是 因为Main()构造函数是在调用super()之前调用的,所以Main初始化块应该是第一个。 问题答案: 不会。初始化块直接复制到构造函数中。显然那里也有一个隐式

  • 问题内容: 我想以异步方式初始化模块,并提出一些想法。我需要具有Mongo集合列表和其他数据的DB对象,但是为了简洁起见,其中的文件列表确实有用。 我无法导出函数或类,因为我每次都需要返回相同的对象。 首先 想到的最简单的方法是分配给它,然后填充它: 不好的事情–我真的从外面不知道什么时候准备好列表,也没有检查错误的好方法。 *我想出的 *第二种 方法是继承并通知所有人数据库已准备就绪或发生了错误

  • 问题内容: 我有多个上下文文件。要求是:在其余的Bean中首先初始化一个特定的Bean(进行一些配置更改)。 有没有一种方法可以首先加载该bean? 一种选择是使用“取决于”属性。 但这将需要更新所有其他bean,因此这似乎不是最佳解决方案。 我们有更好的选择吗? 问题答案: 恕我直言,您应该等待它们修复https://jira.spring.io/browse/SPR-3948 一种可能的方法是

  • 问题内容: 我正在尝试发现初始化发生的顺序,或者更确切地说,为什么要按此顺序进行初始化的原因。给定代码: 输出: 但是,将的声明移动到初始化块之前会产生: 而且我完全不知道为什么会以这种顺序发生。此外,如果我在的声明中消除了关键字,则init块和构造函数均不会触发。谁能帮我这个忙吗? 问题答案: 我认为您只是缺少JLS的12.4.2节,其中包括: 接下来,以文本顺序执行类的类变量初始化器和静态初始

  • 问题内容: 这是一段Java代码: 它如何编译?初始化后已执行变量“ ture”的声明。据我所知,静态块和字段已经按照它们出现的顺序执行了。 现在,为什么实例块中的值9已被打印3次?顺便说一句,该类的实例已创建了3次。那不是功课,我正在学习Java进行认证。 问题答案: 关于第一个问题,静态块确实按照它们出现的顺序进行处理,但是在处理静态块之前,先处理声明。声明作为类 准备工作 的一部分(JLS§