python怎么将if和try一起用_Python使用try/catch还if效率更高一些?
“請求原諒”和“三思而后行”(有時也稱為“請求許可”)是編寫代碼的兩種相反的方法。如果你“三思而后行”,你首先要檢查一切是否設置正確,然后再執(zhí)行一個操作。例如,您要從文件中讀取文本。那會出什么問題呢?好吧,文件可能不在您期望的位置。因此,首先檢查文件是否存在:
import os
if os.path.exists("path/to/file.txt"):
...
# Or from Python 3.4
from pathlib import Path
if Path("/path/to/file").exists():
...
即使文件存在,也許你沒有打開它的權限?所以讓我們看看你是否能讀到:
import os
if os.access("path/to/file.txt", os.R_OK):
...
但是如果文件損壞了怎么辦?或者你沒有足夠的內(nèi)存去讀它?這個名單可以繼續(xù)下去。最后,當你認為你檢查了每一個可能的問題,你可以打開并閱讀它:
with open("path/to/file.txt") as input_file:
return input_file.read()
根據(jù)您要執(zhí)行的操作,可能需要執(zhí)行很多檢查。即使你認為你已經(jīng)涵蓋了所有內(nèi)容,也不能保證某些意外的問題不會阻止你閱讀此文件。所以,你可以“請求原諒”,而不是做所有的檢查
有了“請求原諒”,你什么都不檢查。您可以執(zhí)行您想要的任何操作,但將其包裝在try/catch塊中。如果發(fā)生異常,則處理它。您不必考慮所有可能出錯的地方,您的代碼要簡單得多(沒有更多嵌套的ifs),而且這樣通常會捕獲更多的錯誤。這就是為什么Python社區(qū)通常更喜歡這種方法,通常稱為“EAFP”——“請求原諒比請求許可更容易?!?/p>
下面是一個使用“請求原諒”方法讀取文件的簡單示例:
try:
with open("path/to/file.txt", "r") as input_file:
return input_file.read()
except IOError:
# Handle the error or just ignore it
這里我們正在捕捉IOError。如果您不確定可以引發(fā)哪種類型的異常,可以使用BaseException類捕捉所有異常,但一般來說,這是一種不好的做法。它將捕捉所有可能的異常(例如,當你想停止進程時,包括KeyboardInterrupt),所以盡量更具體一些。
“請求原諒”更干凈。但是哪一個更快?
“請求原諒”與“三思而后行”-速度
是時候做個簡單的測試了。假設我有一個類,我想從這個類中讀取一個屬性。但是我使用的是繼承,所以我不確定是否定義了屬性。我需要保護自己,要么檢查它是否存在(“三思而后行”),要么抓住AttributeError(“請求原諒”):
# permission_vs_forgiveness.py
class BaseClass:
hello = "world"
class Foo(BaseClass):
pass
FOO = Foo()
# Look before you leap
def test_lbyl():
if hasattr(FOO, "hello"):
FOO.hello
# Ask for forgiveness
def test_aff():
try:
FOO.hello
except AttributeError:
pass
我們來測量這兩個函數(shù)的速度。
$ python -m timeit -s "from permission_vs_forgiveness import test_lbyl" "test_lbyl()"
2000000 loops, best of 5: 155 nsec per loop
$ python -m timeit -s "from permission_vs_forgiveness import test_aff" "test_aff()"
2000000 loops, best of 5: 118 nsec per loop
你先看一下,再慢一點。
如果我們增加檢查數(shù)量會怎么樣?假設這次我們要檢查三個屬性,而不僅僅是一個:
# permission_vs_forgiveness.py
class BaseClass:
hello = "world"
bar = "world"
baz = "world"
class Foo(BaseClass):
pass
FOO = Foo()
# Look before you leap
def test_lbyl2():
if hasattr(FOO, "hello") and hasattr(FOO, "bar") and hasattr(FOO, "baz"):
FOO.hello
FOO.bar
FOO.baz
# Ask for forgiveness
def test_aff2():
try:
FOO.hello
FOO.bar
FOO.baz
except AttributeError:
pass
$ python -m timeit -s "from permission_vs_forgiveness import test_lbyl2" "test_lbyl2()"
500000 loops, best of 5: 326 nsec per loop
$ python -m timeit -s "from permission_vs_forgiveness import test_aff2" "test_aff2()"
2000000 loops, best of 5: 176 nsec per loop
“三思而后行”現(xiàn)在大約慢了85%(326/176≈1.852)。所以“請求原諒”不僅更容易閱讀,而且在很多情況下,速度也更快。是的,你讀得對,“在很多情況下,”不是“在所有情況下”!”
“EAFP”和“LBYL”的主要區(qū)別
如果屬性實際上沒有定義,會發(fā)生什么?看看這個例子:
# permission_vs_forgiveness.py
class BaseClass:
pass # "hello" attribute is now removed
class Foo(BaseClass):
pass
FOO = Foo()
# Look before you leap
def test_lbyl3():
if hasattr(FOO, "hello"):
FOO.hello
# Ask for forgiveness
def test_aff3():
try:
FOO.hello
except AttributeError:
pass
$ python -m timeit -s "from permission_vs_forgiveness import test_lbyl3" "test_lbyl3()"
2000000 loops, best of 5: 135 nsec per loop
$ python -m timeit -s "from permission_vs_forgiveness import test_aff3" "test_aff3()"
500000 loops, best of 5: 562 nsec per loop
形勢已經(jīng)好轉?!罢埱笤彙爆F(xiàn)在是“三思而后行”的四倍多(562/135≈4.163)。這是因為這一次,我們的代碼拋出了一個異常。而且處理異常的成本很高。
如果您希望您的代碼經(jīng)常失敗,那么“三思而后行”可能會快得多。
決斷
“請求原諒”的結果是代碼更簡潔,更容易發(fā)現(xiàn)錯誤,而且在大多數(shù)情況下,速度更快。難怪EAFP(“請求原諒比請求許可更容易”)在Python中是如此普遍的模式。即使在本文開頭的示例中(檢查文件是否存在os.path.exists)-如果您查看exists方法的源代碼,就會發(fā)現(xiàn)它只是使用try/except?!叭级笮小蓖ǔе麓a較長,可讀性較差(使用嵌套的if語句)且速度較慢。按照這種模式,你有時可能會漏掉一兩個判斷。
請記住,處理異常是緩慢的。捫心自問:“這段代碼是否會拋出異常更常見?如果答案是“是”,你可以用一個好的“IF”來解決這些問題,太好了!但在很多情況下,你無法預測你會遇到什么問題。使用“請求原諒”是非常好的-在你開始加速之前,你的代碼應該是“正確的”。
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
以上是生活随笔為你收集整理的python怎么将if和try一起用_Python使用try/catch还if效率更高一些?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python读写xlsx文件_pytho
- 下一篇: micropython微控制器_Micr