Python中实现输入超时及如何通过变量获取变量名

yipeiwu_com5年前Python基础

背景介绍

开发中遇到了一个需求:程序运行到某处时需要用户确认, 但不能一直傻等, 后面的程序不能被一直阻塞, 需要有个超时限制, 也就是这个程序如果在一段时间后还没有得到用户输入就执行默认操作.

解决思路 – 多线程法

我就想到了用多线程的方式, 开启一个子线程用stdin(比如python的input函数)获取用户输入, 主线程里设置线程启动和超时.

创建线程

Python中使用多线程很方便, threading.Threaded(函数, 参数表)然后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中的变量大致可以理解成给内容贴上标签(每个标签对应一个变量名, 多个标签可能会引用同一个内容, 没被引用的内容就会被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-变量名字典[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中实现输入超时及如何通过变量获取变量的名字,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对【听图阁-专注于Python设计】网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

相关文章

Python3 翻转二叉树的实现

Python3 翻转二叉树的实现

提出问题:翻转一棵二叉树。(除根结点以外) 原始二叉树: 新二叉树: 解题思路:遇见二叉树先想到递归。从最下层的叶子结点开始置换左右子节点,一直置换到到最上层的根结点的左右节点为止...

运动检测ViBe算法python实现代码

运动检测ViBe算法python实现代码

运动物体检测一般分为背景建模和运动物体分析两步。即构建不包含运动物体的背景模型。然后将新的视频帧和背景模型对比,找出其中的运动物体。目前比较好的背景建模算法有两种:1)文章(Zivkov...

python读取大文件越来越慢的原因与解决

python读取大文件越来越慢的原因与解决

背景: 今天同事写代码,用python读取一个四五百兆的文件,然后做一串逻辑上很直观的处理。结果处理了一天还没有出来结果。问题出在哪里呢? 解决: 1. 同事打印了在不同时间点的时间,在...

用Python实现校园通知更新提醒功能

用Python实现校园通知更新提醒功能

前言 这个项目实已经在一个月前已经完成了,一直都想写一篇博客来总结这个过程中遇到的一些问题。但最近一个月来都比较忙,所以一直拖到了现在。 首先说说起因吧,我没事的时候,总喜欢依次点开学校...

windows环境中利用celery实现简单任务队列过程解析

windows环境中利用celery实现简单任务队列过程解析

这篇文章主要介绍了windows环境中利用celery实现简单任务队列过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一、背景...