比如我现在有这么一个需求,我在一个方法中一直循环探测一个服务的连接数,当连接数为0时,就继续走下面的逻辑,比如关闭服务操作,以此来做 Java 平滑发布。伪代码如下:
1 2 3 4 5 6 7 |
def fun(): while True: processlist = 'netstat -anplt | wc -l' time.sleep(1) if processlist == 0: kill service pid |
可以看出来,如果说条件不为真,就一直循环了。这里我们就可以提供一个ctrl+c操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def fun(): while True: try: import time processlist = 'netstat -anplt | wc -l' print(processlist) time.sleep(1) except KeyboardInterrupt: iskill = 1 break if iskill == 1: print("kill service pid") elif processlist == 0: print("kill service pid") return |
这样的一个优点就是,ctrl+c 只对 while 循环生效,不在此循环内的 ctrl+c 操作,就会被系统捕获到。
也可以使用 signal 模块实现,但属于一个全局的 ctrl+c 捕获。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import time import signal def sigint_handler(signum, frame): global is_sigint_up is_sigint_up = True print('catched interrupt signal!') signal.signal(signal.SIGINT, sigint_handler) signal.signal(signal.SIGHUP, sigint_handler) signal.signal(signal.SIGTERM, sigint_handler) is_sigint_up = False def fun(): global is_sigint_up while True: try: # 你要做的事情 print("start .............") time.sleep(1) # 捕获到ctrl+c之后要做的事情 if is_sigint_up: print("Exit") break except: print(10) break # 跳出循环之后要做的事情 while True: print("next") time.sleep(1) print(fun()) |
需要注意一点的就是全局变量的问题,全局变量和局部变量两者的本质区别就是在于作用域。
用通俗的话来理解的话,全局变量是在整个 py 文件中声明,全局范围内都可以访问。局部变量是在某个函数中声明的,只能在该函数中调用它,如果试图在超出范围的地方调用,程序就会异常了。如果在函数内部定义与某个全局变量一样名称的局部变量,就可能会导致意外的效果,可能不是你期望的。因此不建议这样使用,这样会使得程序很不健全。
1 2 3 4 5 6 7 |
gcount = 0 def global_test(): gcount += 1 print(gcount) global_test() |
如果执行会报,UnboundLocalError: local variable ‘gcount’ referenced before assignment。
我们首先定义了一个全局变量,(可以省略global关键字)。在 global_test 函数中程序会因为“如果内部函数有引用外部函数的同名变量或者全局变量,并且对这个变量有修改,那么 Python 会认为它是一个局部变量,又因为函数中没有 gcount 的定义和赋值,所以报错。
声明全局变量,如果在局部要对全局变量修改,需要在局部也要先声明该全局变量:
1 2 3 4 5 6 7 8 |
gcount = 0 def global_test(): global gcount gcount += 1 print(gcount) global_test() |
如果在函数中声明 gcount 是全局变量,即可对其进行修改,正确输出 1 。
在局部如果不声明全局变量,并且不修改全局变量,则可以正常使用全局变量。
再看看另一个跟变量相关的关键字 nonlocal,字面意思就是指当前的这个变量不是局部变量。nonlocal 是 Python 3.0 中新增的关键字,Python 2.x 不支持。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
def make_counter(): count = 0 def counter(): count += 1 return count return counter def make_counter_test(): mc = make_counter() print(mc()) print(mc()) print(mc()) make_counter_test() |
此代码同样会报错,错误的原因跟前面的差不多,就是使用了未定义的局部变量,然而 count 也不是全局变量,只是 counter 函数的外层变量,如果强行使用 global 定义 count 变量的话同样会报错,会报 name ‘count’ is not defined 。
这时候就需要使用 nonlocal 关键字了,nonlocal 用来在函数或其他作用域中使用外层(非全局)变量,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter def make_counter_test(): mc = make_counter() print(mc()) print(mc()) print(mc()) make_counter_test() |
会输出结果 1、2、3。
关键字 nonlocal 适用于在局部函数中的局部函数,把最内层的局部变量设置成外层局部可用,但是还不是全局的。
或者你这么使用 global 关键字。在函数 make_counter 内 global 定义的变量 count,只能在函数 counter 内引用,如果要在 counter 内修改,必须在 counter 函数里面声明 global count ,表明是修改外面的全局变量 count。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def make_counter(): global count count = 0 def counter(): global count count += 1 return count return counter def make_counter_test(): mc = make_counter() print(mc()) print(mc()) print(mc()) make_counter_test() |
global 定义的变量,表明其作用域在局部以外,即局部函数执行完之后,不销毁函数内部以 global 定义的变量:
1 2 3 4 5 6 |
def make_counter(): global count count = 0 make_counter() print(count) |
Python 引用变量的顺序:当前作用域局部变量 -> 外层作用域变量 -> 当前模块中的全局变量 -> Python内置变量。