tft每日頭條

 > 科技

 > python編程例子簡單

python編程例子簡單

科技 更新时间:2024-10-17 20:20:23

經過了前面3次課對數位輸入與回退的處理,我們的計算器已經可以基本正常地輸入數字了(輸入别太長),這次讓我們實現它的計算功能。

python編程例子簡單(python窗口編程-6計算功能)1

計算功能需求分析

第一步,仍然是對計算功能的需求做一個分析。簡化起見,我們隻實現普通計算器功能:它的内部不區分算符優先級。比如你依次按下3 5*2幾個按鈕,在你按下*的時候,計算機會把3 5的結果直接計算出來,并顯示為8,沒有考慮*的優先級問題。

python編程例子簡單(python窗口編程-6計算功能)2

常見的太陽能計算器大都是這個計算邏輯

包括win10自帶的計算器,其操作邏輯也是一樣的。

python編程例子簡單(python窗口編程-6計算功能)3

計算器最典型的操作,是輸入數字1,按一個運算符按鈕( ,-,*,/),再輸入數字2,按等于按鈕,屏幕顯示結果。

我們分析一下計算器的典型操作方法。這種分析一方面有助于我們設計合理的計算模型,另一個方面,可以指定我們的測試工作。

  • 第一,接續運算,就如同我們上面的動畫演示一樣,數字 運算符 數字 運算符 數字,可以多個,最後再按等于按鈕,顯示結果。其實,這種情況中,每次按運算符按鈕時,中間的結果都被計算并顯示出來,等于按鈕隻是做最後一步的運算。
  • 第二,連續等于,大概經常用于無聊又無事可做的時候:連續按等于按鈕,計算器就會持續用同一個規則進行計算。如下:

python編程例子簡單(python窗口編程-6計算功能)4

  • 第三,在連續等于的操作後,如果我們輸入一個數字,立即又按等于按鈕,我們發現:這個新輸入的數字被當作第一操作數來處理。以前門的操作為例:72-1-1-1-1之後,如果我們按數字5,再連續按等于,我們發現結果将是5,4,3,2,1,0,-1這個順序變化。即運算符(-)和第二操作數(1)均保持不變。
  • 第四,在接續運算的操作中,運算符按鈕的作用從含義上等價于先按了等于按鈕再按按運算符按鈕;但在連續等于的操作中,這裡如果按運算符按鈕,卻沒有連續計算的效果。經過思考和比較,我們發現,兩者的區别是在兩次按運算符之間是否輸入過數字
  • 第五,在輸入運算符後,如果不輸入數字,直接按等于,是可以進行運算的。這種情況下,第一、二操作數是相同。即按等于按鈕的時候,當前顯示屏上的數字被理解為第二操作數。比如我們想計算9 9的結果,我們可以這樣按鍵9 =。
  • 第六,按下運算符按鈕或者等于按鈕之後,繼續按數字鍵或小數點鍵不會繼續改變這個數字,而是重新開始輸入數字。這一現象提示我們,這裡可能存在一個内部狀态的改變。
編程模型設計

設計編程模型中的一個非常混淆難解的問題是,把本質不同的概念用不同的變量表示,把本質相同的概念用一個變量表示。之所以它混淆難解,在于兩個概念的本質究竟是否相同,從不同的角度看,是不一樣。這個問題,在我們編程的過程中會持續存在,始終推動編程者去思考究竟一個概念的本質是什麼。這也是編程對思維的訓練效果之一。

1、按鈕事件分類

現在看我們設計計算器計算功能的編程模型。我們發現四個運算符按鈕( ,-,*,/)的本質是相同的,這個相同,指的是按下按鈕後,操作邏輯完全相同,唯一的區别是計算的方法不一樣。而運算按鈕和等于按鈕則有着本質的區别,比如前面需求中的第四點,明确表現了這種區别。所以我們的條件判斷分成兩類:

elif event in [' ', '-', '*', '/']: #按運算符的處理 elif event in ['=']: #按等于的處理

2、表達式

根據需求,我們看到,隻須建立一個簡單的表達式模型,它有三個成分:

  1. 第一操作數
  2. 運算符
  3. 第二操作數

我們用一個字典變量來記錄這個内部表達式,它也是一個全局變量。

expr= {'opnd1':None, 'optr': None, 'opnd2':None}

它的初始值可以為空,當計算的時候,我們用這個一個函數。

def doCalc(expr): optr= expr['optr'] opnd1= expr['opnd1'] opnd2= expr['opnd2'] if optr is None: result= opnd1 elif optr==' ': result= opnd1 opnd2 elif optr=='-': result= opnd1- opnd2 elif optr=='*': result= opnd1* opnd2 elif optr=='/': result= opnd1/ opnd2 return result

我們設計的init函數,使用了全局變量。可以說那是為了代碼簡化而采取的一個做法。如果有可能,我們希望函數盡量不使用全局變量。因為這樣的函數獨立性更強,我們很容易重用、也很容易轉移到其它的文件中。

這個函數的實現用了一個簡單的笨辦法:用if語句判斷運算符是什麼,根據不同的運算符做不同的計算。這樣的代碼當然不夠簡潔,但它可控性是比較好的。我們可以在編程的初期使用這種實現方法,在主體邏輯通順後,可以對它進行優化。

3、内部狀态

狀态設計是編程模型設計的一個重點,一個系統的複雜性在很大程度上就表現為内部狀态的多少。同樣的外部輸入,會得到不同的結果,這才給人以複雜的感覺——其原因就是内部狀态的不同。這裡說的複雜性與算法設計意義上常說的時間複雜性空間複雜性不是類似的概念。從編程的角度來說,系統内部狀态的複雜性是有辦法把握的,是人力可為的;而時空複雜性雖然可以通過優化算法有一定幅度(甚至是很大幅度)的改變,但從本質上是有着不可逾越的瓶頸的。

除了剛才設置的表達式變量,我們再回顧一下前面課程中,為了控制數字的輸入,已經建立了三個變量來描述系統的内部狀态:

  • value:數值
  • sign:正負号
  • decNum:小數位

從需求分析看,我們至少還需增加這樣兩個内部狀态:

  • 1、當前輸入數字按鈕時,是重新開始一個新的數字,還是繼續屏幕上的數字。我們可以設置一個state(狀态)變量,它有兩個值:0代表開始一個新的數字,1代表繼續輸入。

如果是開始一個新的數字,我們将進行一個類似的初始化操作,寫成函數是:

def initNum(): global value, decNum, sign, state value= 0 decNum= 0 sign= 1 state= 1

我們體會一下它的用法和功能,會發現,這個函數的本質是計算器的CE按鈕。幾乎所有的計算器都有AC和CE兩個按鈕,AC代表完全的清空,恢複開機狀态(init)。CE則代表清除剛才輸入的數字。由于我們的計算器是一個極簡版,所以并沒有包括CE按鈕,但不影響這個功能的内部存在。

  • 2、當前輸入的這個數字,是第一操作數還是第二操作數。我們設置變量pos(位置),它有兩個值:分别是opnd1和opnd2,分别對應着兩個操作數。這樣定值的好處是我們可以直接用這個變量把數字輸入表達式對應的位置中。

它的代碼就是這樣一句:

expr[pos]= sign*value

值得注意的是,value本身隻是輸入數據的絕對值,必須和sign相乘才是真正的輸入數。

代碼實現

最後看一代碼下實現。當點擊運算符按鈕時,操作邏輯如下:

elif event in [' ', '-', '*', '/']: expr[pos]= sign*value if pos=='opnd2' and state==1: value= doCalc(expr) expr['opnd1']= value expr['optr']= event pos= 'opnd2' state= 0 sign= 1

當輪到第二操作數并且确實輸入了數字(見需求4)則觸發運算,并把結果作為新的第一操作數。第一操作數是不觸發運算的。其它工作是記錄操作符,并标記新的位置是第二操作數,狀态置0的意思是切換到新數字模式。

當點擊等于按鈕時,操作邏輯如下:

elif event in ['=']: expr[pos]= sign*value value= doCalc(expr) pos= 'opnd1' state= 0 sign= 1

點擊等于按鈕後,操作數位置變為第一個,這對應着需求3的實現。

為什麼把結果賦值給了value呢?因為我們的屏幕顯示部分,直接用value來顯示。

為什麼必須置sign=1呢?也與顯示有關。在計算-1*8的時候沒有問題,當計算8*-1的時候,如果沒有這個設置,我們會發現一個奇怪的現象!有興趣的朋友可以自己修改代碼,看看會出現什麼現象。[呲牙]

加上了這些内部變量,再加上這兩小段事件處理代碼,我們的計算器終于可以有了一些真正的計算功能。so far so good。我們可以試試整數的加法、減法、乘法,對比一下真實的計算器,看看是否一緻。但這裡還沒有真正處理涉及小數的計算,朋友們可以試試當進行小數計算時會出現哪些問題,嘗試自己解決它們。我們把這一功能的分析留待下次課程。

最後貼一下目前為止的完整代碼。

python編程例子簡單(python窗口編程-6計算功能)5

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved