Python实现输入超时与动态修改变量及获取变量名的方法
本文介绍在Python中实现用户输入超时限制的方法,利用多线程机制避免主程序阻塞。同时探讨如何在非全局作用域下通过变量值动态获取变量名并修改其内容,通过构建ID映射字典实现通用化的变量修改函数,适用于需要灵活控制程序流程的场景。
背景介绍
在开发过程中,常遇到需要用户确认但又不希望程序无限期阻塞的情况。例如,程序运行至某一步骤时需等待用户输入,若超时未收到输入则执行默认操作,后续程序不应被一直阻塞。
解决思路 – 多线程法
采用多线程方案,开启一个子线程通过stdin(如Python的input函数)获取用户输入,主线程中设置线程启动及超时控制。
创建线程
Python中创建多线程十分便捷,使用threading.Thread(函数, 参数表)后调用thread.start()即可。需注意,参数表必须为元组,即每个元素后需跟随逗号。
import threading
def anyFunction(aaa):
return str(aaa) #某种处理结果, 比如字符串
def manualInput(xxx):
data = input("请输入%s: " % xxx)
pass # 各种处理(比如数据转换什么的)
exampleThread = threading.Thread(target = manualInput, args = ( anyFunction("汪汪汪"), ), name = "喵喵喵")
exampleThread.start()
通过函数修改指定变量的值 然而,若不使用全局变量,如何在另一个函数中修改其参数对应的内容?核心问题在于“函数如何修改自身参数的内容”。
这里提出一种方法——修改变量字典。Python中的变量基于标签机制,可理解为给内容贴上标签(每个标签对应一个变量名,多个标签可能引用同一内容,未被引用的内容会被Python释放)。每个标签拥有唯一的id(同时,被引用的内存数据也有其自身的id)。示例:
print(id("喵喵喵"),"~~", id("喵喵喵"),"~~", id("喵喵喵"),"~~")
[Out]:
1392371317520 ~~ 1392371317520 ~~ 1392371317520 ~~
print(id("喵喵喵")); print(id("喵喵喵")); print(id("喵喵喵"))
[Out]:
1392371318576
1392371318000
1392371318288
Python通过字典方式维护标签与内容的对应关系,修改globals()[待改变量的原名]的值即可通过指定变量名修改变量。

通过globals字典修改变量
通过变量获取变量名(字符串) 上述通过globals()[待改变量的原名] = 新内容的方式实现了修改变量内容,但待改变量的原名是字符串,如何从变量本身得到其变量名?
一种思路是使用字典法。
复制当前运行环境中的所有变量(浅拷贝和深拷贝效果相同,因为拷贝前后标签一致),新建一个“标签id-变量名”对照表字典。利用字典赋值特性,遍历复制的全局变量,将id(变量值)作为key,变量名作为value,即内容_变量名字符串对照表[id(变量值)] = 变量名。
test = "some values"
变量A = "汪汪汪"
当前所有变量 = globals().copy()
print(当前所有变量)
[Out]:
{'__name__': '__main__',..., 'test': 'some values', '变量A': '汪汪汪'}
内容_变量名字符串对照表 = {}
for 变量名, 变量值 in 当前所有变量.items():
内容_变量名字符串对照表[id(变量值)] = 变量名
print(内容_变量名字符串对照表)
[Out]:
{2437914516272: '__name__',..., 2437948462576: 'test', 2437948432816:'变量A'}
由此建立内容到变量名字符串的对照表。由于id(变量A)与id(变量A的值)相等,利用此特性即可通过变量获取变量名。
变量A的值 = 变量A print(id(变量A的值) [Out]: 2437948432816 内容_变量名字符串对照表[id(变量A的值)] [Out]: '变量A'
通过函数修改变量
上述逻辑旨在动态、通用地修改变量,封装为函数后可在任何地方调用和修改。
def 一个实现变量修改函数(要改的变量, 提示语):
当前所有变量 = globals().copy()
变量id表 = {}
for 变量名, 变量值 in 当前所有变量.items():
变量id表[id(变量值)] = 变量名
待改的变量的原名 = 变量id表[id(要改的变量)]
新的内容 = str(input(提示语))
if len(新的内容) > 0 :
globals()[待改的变量的原名] = 新的内容
return 待改的变量的原名
tmp = "汪汪汪"
一个实现变量修改函数(tmp, "请输入新值: ")
[Out]: 请输入新值: 喵喵喵 'tmp' print(tmp) [Out]: 喵喵喵
总结(demo)[若不想看中间过程可直接查看此处]
import time, threading
# 这里的demo是为了通用化. 因为在一个线程中再嵌套另个线程的话, 嵌套的线程获取不到所有变量
class ThreadWithReturn(threading.Thread):
def __init__( self, target = None, args = () ):
super(ThreadWithReturn,self).__init__()
self.func = target
self.args = args
def run(self):
self.result = self.func(*self.args)
def getResult(self):
try:
return self.result
except Exception as errInfo:
print("遇到错误: ", errInfo)
return None
def 一个实现变量修改函数(要改的变量, 提示语):
当前所有变量 = globals().copy()
变量id表 = {}
for 变量名, 变量值 in 当前所有变量.items():
变量id表[id(变量值)] = 变量名
try:
待改的变量的原名 = 变量id表[id(要改的变量)]
except KeyError:
print("***debug: 在不同的线程中运行, 获取不到出入变量的名字")
待改的变量的原名 = None
新的内容 = str(input(提示语))
if len(新的内容) > 0 :
if 待改的变量的原名 != None:
globals()[待改的变量的原名] = 新的内容
else:
新的内容 = None
return [待改的变量的原名, 新的内容]
def Gexit():
exitConfirm = "u"
waitForConirm = ThreadWithReturn( target = 一个实现变量修改函数, args = (exitConfirm, "收到了退出信号, 默认30秒后退出, 是否现在退出呢? (Y/n) 请输入: ",) )
waitForConirm.start()
waitForConirm.join(30)
try:
exitConfirm = waitForConirm.getResult()[1]
print("***debug, got:", exitConfirm)
except Exception as errInfo:
print("***debug:", errInfo)
exitConfirm = "u"
if exitConfirm == "u":
print("等待超时, 开始退出流程...")
exitConfirm = "Ytt"
if exitConfirm == "Ytt" or exitConfirm == "Y":
if exitConfirm == "Y":
print("确认退出, 开始退出流程...")
pass # 这里放程序退出逻辑
if exitConfirm == "n":
print("取消退出, 继续运行...")
pass # 这里放继续运行的逻辑
return 0
Thread_waitForExit = threading.Thread(target = Gexit, args = ())
Thread_waitForExit.start()
Thread_waitForExit.join(45)
总结
以上介绍了Python中实现输入超时及通过变量获取变量名的方法,希望有所帮助。如有疑问请留言,小编会及时回复。感谢大家对本站的支持! 若本文对您有帮助,欢迎转载,请注明出处,谢谢!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













