使用 Linkbot 學習 Python 3/處理不完美
with open("in_test.txt", "rt") as in_file:
with open("out_test.txt", "wt") as out_file:
text = in_file.read()
data = parse(text)
results = encode(data)
out_file.write(results)
print( "All done." )
如果在這段程式碼中的任何地方發生了某種錯誤(其中一個檔案無法訪問,parse()函式因損壞的資料而阻塞等等),“with”語句保證所有檔案最終都會被正確關閉。關閉檔案只是意味著檔案被我們的程式“清理”和“釋放”,以便它可以在另一個程式中使用。
因此,您現在有了完美的程式,它執行得非常完美,除了一個細節,它會在無效的使用者輸入時崩潰。不要害怕,因為 Python 為您提供了一個特殊的控制結構。它叫做 try,它會嘗試做某事。這是一個有問題的程式的示例
print("Type Control C or -1 to exit")
number = 1
while number != -1:
number = int(input("Enter a number: "))
print("You entered:", number)
注意,當您輸入 @#& 時,它會輸出類似以下的內容
Traceback (most recent call last):
File "try_less.py", line 4, in <module>
number = int(input("Enter a number: "))
ValueError: invalid literal for int() with base 10: '\\@#&'
如您所見,int() 函式對數字 @#& 不滿意(理所當然)。最後一行顯示了問題所在;Python 發現了一個 ValueError。我們的程式如何處理這種情況?我們要做的第一件事是:將可能發生錯誤的地方放在 try 塊中,第二件事是:告訴 Python 我們希望如何處理 ValueError。以下程式就是這樣做的
print("Type Control C or -1 to exit")
number = 1
while number != -1:
try:
number = int(input("Enter a number: "))
print("You entered:", number)
except ValueError:
print("That was not a number.")
現在,當我們執行新程式並提供 @#& 時,它會告訴我們“這不是一個數字”,並繼續之前正在做的事情。
當您的程式不斷出現您知道如何處理的錯誤時,請將程式碼放在 try 塊中,並將處理錯誤的方式放在 except 塊中。
我們在前面的示例中已經看到,我們可以編寫一個函式,使輪式機器人行駛一定距離。我們還可以使用 setJointSpeed() 函式控制電機轉速。setJointSpeed() 函式期望以度/秒為單位的轉速,但如果我們可以使用英寸/秒為單位來設定機器人速度,那就更好了。將 英寸/秒轉換為 度/秒的數學公式為
其中 是輪子半徑。讓我們擴充套件來自 使用 Linkbot 學習 Python 3/定義函式 部分的示例
術語 字元 是“omega”,通常用於表示轉速。通常, 的單位是弧度/秒,但在本例中,單位是度/秒。 |
import barobo
import math # So that we can use math.pi
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('abcd') # Change abcd to your Linkbot's serial ID
def driveDistance(linkbot, distance):
r = 3.5 / 2 # If you have a wheel that's not 3.5 inches in diameter, change "3.5" to the diameter of your wheel
degrees = (360) / (2 * math.pi * r) * distance
linkbot.move(degrees, 0, -degrees)
def setSpeed(linkbot, speed):
r = 3.5 / 2
omega = (speed/r) * (180/math.pi)
linkbot.setJointSpeed(1, omega)
linkbot.setJointSpeed(3, omega)
setSpeed(myLinkbot, 2.5) # Sets the speed to 2.5 inches/sec
driveDistance(myLinkbot, 10) # Drives the Linkbot 10 inches forward
driveDistance(myLinkbot, -5) # Drives the Linkbot 5 inches backward
這個示例很好。我們定義了一個名為 setSpeed() 的新函式,它設定 Linkbot 輪式車輛的速度,我們使用它將速度設定為 2.5 英寸/秒。
如果程式設計師嘗試將速度設定為 1000 英寸/秒?或者 1000000 英寸/秒?儘管看到 Linkbot 與一級方程式賽車競爭會很酷,但 Linkbot 的電機在物理上無法超過 200 度/秒。如果速度過高,我們應該設定一個使用者可以看到並可能處理的錯誤。這叫做“引發異常”。引發異常的程式碼如下所示
def setSpeed(linkbot, speed):
r = 3.5 / 2
omega = (speed/r) * (180/math.pi)
if omega > 200:
raise Exception('The speed is too high!')
linkbot.setJointSpeed(1, omega)
linkbot.setJointSpeed(3, omega)
當引發異常時,函式立即返回異常。這些引發的異常可以被 try/except 塊捕獲。如果異常發生在 try/except 塊之外,整個程式將退出並顯示異常的錯誤訊息。在 setSpeed() 函式中,這意味著如果執行了 raise,則兩個 setJointSpeed() 語句將被跳過。
當我執行新程式並嘗試將速度設定為 1000 英寸/秒時,我得到以下輸出
Traceback (most recent call last):
File "./linkbot_speed.py", line 20, in <module>
setSpeed(myLinkbot, 1000) # Sets the speed to 1000 inches/sec
File "./linkbot_speed.py", line 16, in setSpeed
raise Exception('The speed is too high!')
Exception: The speed is too high!
現在您可以使用 try/catch 塊來處理可能的錯誤。讓我們嘗試編寫一個程式,它嘗試再次將速度設定為 10 英寸/秒,但每次遇到異常時,它都會將請求的速度降低 1 英寸/秒,並再次嘗試。
import barobo
import math # So that we can use math.pi
dongle = barobo.Dongle()
dongle.connect()
myLinkbot = dongle.getLinkbot('ABCD') # Change ABCD to your Linkbot's serial ID
def driveDistance(linkbot, distance):
r = 3.5 / 2 # If you have a wheel that's not 3.5 inches in diameter, change "3.5" to the diameter of your wheel
degrees = (360) / (2 * math.pi * r) * distance
linkbot.move(degrees, 0, -degrees)
def setSpeed(linkbot, speed):
r = 3.5 / 2
omega = (speed/r) * (180/math.pi)
if omega > 200:
raise Exception('The speed is too high!')
linkbot.setJointSpeed(1, omega)
linkbot.setJointSpeed(3, omega)
requestedSpeed = 10 # 1
while True: # 2
try:
print('Trying to set speed to: ' + str(requestedSpeed) + 'inches/sec')
setSpeed(myLinkbot, requestedSpeed) # 3
print('Success!')
break # 4
except:
print('Failed.')
requestedSpeed -= 1 # 5
# 6
driveDistance(myLinkbot, 10) # Drives the Linkbot 10 inches forward
driveDistance(myLinkbot, -5) # Drives the Linkbot 5 inches backward
輸出為
Trying to set speed to: 10inches/sec Failed. Trying to set speed to: 9inches/sec Failed. Trying to set speed to: 8inches/sec Failed. Trying to set speed to: 7inches/sec Failed. Trying to set speed to: 6inches/sec Success!
讓我們一起逐步執行這個程式,確保我們完全理解正在發生的事情。
- # 1 : 當我們第一次到達這一行時,我們建立一個名為
requestedSpeed的新變數,並將其值設定為“10”。 - # 2 : 進入無限迴圈
- # 3 : 嘗試設定速度。
requestedSpeed當前為 10,過高。setSpeed()函式丟擲異常。由於我們在 try/except 塊中,因此在丟擲異常後立即轉到 except 塊。繼續執行 # 5 - # 5 : 將
requestedSpeed減少 1。requestedSpeed現在為 9。這是我們while迴圈的結束,這意味著 Python 將返回到迴圈的開頭。 - # 3 : 我們再次回到 # 3,除了
requestedSpeed現在為 9。仍然過高,丟擲異常。 - # 5 : 我們再次將
requestedSpeed減至 8。 - # 3 : 仍然過高...
- # 5 : 減少至 7...
- # 3 : 仍然過高...
- # 5 : 減少至 6。
- # 3 : 現在成功了。由於它成功了,所以沒有丟擲異常。繼續執行 # 4
- # 4 : 此
break語句將我們從迴圈中彈出。繼續執行 # 6 和程式的其餘部分。
至少更新電話號碼程式(在部分 字典 中),以便在使用者在選單中未輸入任何資料時不會崩潰。
