背景介紹
開發中遇到了一個需求:程序運行到某處時需要用戶確認, 但不能一直傻等, 后面的程序不能被一直阻塞, 需要有個超時限制, 也就是這個程序如果在一段時間后還沒有得到用戶輸入就執行默認操作.
解決思路 – 多線程法
我就想到了用多線程的方式, 開啟一個子線程用stdin(比如python的input函數)獲取用戶輸入, 主線程里設置線程啟動和超時.
創建線程
Python中使用多線程很方便, threading.Threaded(函數, 參數表)然后thread.start就好了. 只是有一點需要注意, 上面參數表必須是個元組, 也就是每個元素后面必須跟個逗號.
1
2
3
4
5
6
7
8
9
|
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). 示例:
1
2
3
4
5
6
7
8
|
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(變量值)] = 變量名.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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的值)是相等, 利用這個特性就能通過變量來取變量值了.
1
2
3
4
5
6
7
|
變量A的值 = 變量A print ( id (變量A的值) [Out]: 2437948432816 內容_變量名字符串對照表[ id (變量A的值)] [Out]: '變量A' |
通過函數修改變量
上面這一堆頭發就是為了動態、通用地修改變量, 封裝成函數就能在任何地方調用和修改了.
1
2
3
4
5
6
7
8
9
10
11
|
def 一個實現變量修改函數(要改的變量, 提示語): 當前所有變量 = globals ().copy() 變量 id 表 = {} for 變量名, 變量值 in 當前所有變量.items(): 變量 id 表[ id (變量值)] = 變量名 待改的變量的原名 = 變量 id 表[ id (要改的變量)] 新的內容 = str ( input (提示語)) if len (新的內容) > 0 : globals ()[待改的變量的原名] = 新的內容 return 待改的變量的原名 tmp = "汪汪汪" |
一個實現變量修改函數(tmp, "請輸入新值: ")
1
2
3
4
5
6
|
[Out]: 請輸入新值: 喵喵喵 'tmp' print (tmp) [Out]: 喵喵喵 |
總結(demo)[不想看中間過程的話可以直接看這]
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
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中實現輸入超時及如何通過變量獲取變量的名字,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!
原文鏈接:https://blog.csdn.net/qq_39707057/article/details/104002512