当前位置: ManBetXapp > 百科 > 科技 >正文

python怎么让程序重复运行

人气:410 ℃ /2022-11-24 01:29:37

Python是一门解释性语言,有些时候在现实生活中我们需要进行一些事件的重复,正如常识一样但在现实世界中的事物有自己具象的颜色,形状,不过一旦重复这些事物,一样不可避免的会感到无聊。现实世界尚且如此,编程语言中重复的进程就更不用说了。还好,Python拥有循环结构,可以解决Python中的重复过程,为了学会怎样使程序自己重复运行呢?

方法一:报错后,重新启动.py文件,继续执行

方法二:重复执行本.py文件中的内容

方法三:异常调用函数本身

python怎么让程序重复运行异常调用函数

魔幻离现实仅一步之遥:Python的循环调用、引用和导入

小时候,常被一些可笑的问题困扰——尽管成年以后面临的疑惑更多,但似乎是因为已经适应了在迷茫中前行,对于未解的问题反倒是失去了那种急于想知道答案的迫切感。比如,站在两面相对的镜子中间,会看到无数个自己吗?对于少时的我,这的确是一个非常魔幻的问题,直到理解了光量子能量衰减,才算找到了答案。

近日,有同学咨询Python对象的循环引用以及垃圾回收问题,结合前些日子遇到的循环调用和循环导入问题,在整理答案的时候,我忽然意识到,这几个问题居然和困惑我多年的“两面镜子”问题居然有相通之处:看起来都有些魔幻,转身即是真实的世界!

1. 走向毁灭的函数循环调用

如果多个函数相互调用,构成闭环,就形成了函数的循环调用。下面的例子中,函数a在其函数体中调用了函数b,而函数b在其函数体中又调用了函数a,这就是典型的函数循环调用。

>>> def a(): print('我是a') b() >>> def b(): print('我是b') a() >>> a()

此种情况下,调用函数(无论是a函数还是b函数),会发生什么呢?

>>> a()我是a我是b我是a我是b...... # 此处省略了一千余行Traceback (most recent call last): File "", line 1, in a() File "", line 3, in a b()...... # 此处省略了两千余行RecursionError: maximum recursion depth exceeded while pickling an object

很快你就会发现,运行出现了问题,系统连续抛出异常,大约滚动了几千行之后,终于结束了运行。最后的提示是:

RecursionError: maximum recursion depth exceeded while pickling an object

意思是说,发生了递归错误,在序列化(pickle)对象时超过了最大递归深度。

原来,循环调用类似于递归调用,为了保护堆栈不会溢出,Python环境一般都会设置递归深度保护,一旦查过递归深度,就会抛出递归错误,然后再一层一层退出堆栈。这就是屏幕滚动几千条错误信息的原因。

关于Python环境递归深度,可以通过sys模块查看和设置。

>>> import sys>>> sys.getrecursionlimit()1000>>> sys.setrecursionlimit(500)>>> sys.getrecursionlimit()5002. 同生共死的对象循环引用

函数的循环调用不难理解,而对象的循环引用就有点费解了。什么是对象的循环引用呢?当一个对象被创建时(比如实例化一个类),Python会为这个对象设置一个引用计数器。如果这个对象被引用,比如被关联到一个变量名,则该对象的引用计数器加1,如果关联关系取消,则该对象的引用计数器减1。当一个对象的引用计数器为1时(关于这一点,仅凭个人观察得出,未见权威说法),系统将自动回收该对象。这就是Python的垃圾回收机制。下面的代码,借助于sys模块,可以直观地看到一个列表对象的引用计数器的变化。

>>> import sys>>> a = list('abc')>>> sys.getrefcount(a)2>>> b = a>>> sys.getrefcount(a)3>>> del b>>> sys.getrefcount(a)2

当多个对象存在相互间的成员引用,一旦形成闭环的时候,就会发生所谓对象的循环引用。我们来看一个例子:a和b是类A的两个实例对象,del这两个对象的时候,将会调用对象的__del__方法,最后显示“运行结束”。

class A: def __init__(self, name, somebody=None): self.name = name self.somebody = somebody print('%s: init'%self.name) def __del__(self): print('%s: del'%self.name)a = A('a')b = A('b')del adel bprint('运行结束')

运行结果正如我们所希望的那样。

a: init b: init a: del b: del 运行结束

然而,当我们创建了实例a和b之后,如果将a.somebody指向b,将b.somebody指向a,那么就产生了实例间成员相互引用形成闭环的情况。

class A: def __init__(self, name, somebody=None): self.name = name self.somebody = somebody print('%s: init'%self.name) def __del__(self): print('%s: del'%self.name)a = A('a')b = A('b')a.somebody = bb.sombody = adel adel bprint('运行结束')

运行这段代码,你会发现,del这两个对象的时候,对象的__del__方法并没有被立即执行,而是程序结束之后才被执行的。

a: init b: init 运行结束 a: del b: del

这意味着,在程序运行期间,应该被回收的内存并没有正确回收。这样的问题,属于内存泄漏,应该给予高度重视。通常,我们可以使用gc模块强制回收内存。

import gcclass A: def __init__(self, name, somebody=None): self.name = name self.somebody = somebody print('%s: init'%self.name) def __del__(self): print('%s: del'%self.name)a = A('a')b = A('b')a.somebody = bb.sombody = adel adel bgc.collect()print('运行结束')

再看运行结果,一切正常了。

a: init b: init a: del b: del 运行结束

3. 转圈推磨的模块循环导入

相对而言,模块的循环导入的情况一般极少发生。如果发生,一定是模块的功能分割不合理造成的,通过调整模块的定义,可以很容地解决问题。下面用一个最精简的例子,来演示一下模块循环导入是如何产生的。

名为a.py的脚本文件内容如下:

import bMODULE_NAME = 'a'print(b.MODULE_NAME)

名为b.py的脚本文件内容如下:

import aMODULE_NAME = 'b'print(a.MODULE_NAME)

两个脚本互相引用,并且各自使用了对方定义的常量MODULE_NAME。无论我们运行哪个脚本,都会因为模块的循环导入而无法正确执行。

Traceback (most recent call last): File “a.py”, line 1, in import b File “D:\temp\csdn\b.py”, line 1, in import a File “D:\temp\csdn\a.py”, line 4, in print(b.MODULE_NAME) AttributeError: module ‘b’ has no attribute ‘MODULE_NAME’

多说一句,很多人学Python过程中会遇到各种烦恼问题,没有人解答容易放弃。小编是一名python开发工程师,这里有我自己整理了一套最新的python系统学习教程,包括从基础的python脚本到web开发、爬虫、数据分析、数据可视化、机器学习等。想要这些资料的可以关注小编,并在后台私信小编:“01”即可领取。

搜索更多有关“ python怎么让程序重复运行”的信息 [百度搜索] [SoGou搜索] [头条搜索] [360搜索]
CopyRight © 2008-2024 ManBetXappAll Rights Reserved. 手机版