<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](library.xhtml "代碼庫和插件 FAQ") | - [上一頁](programming.xhtml "編程常見問題") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 常見問題](index.xhtml) ? - $('.inline-search').show(0); | # [設計和歷史常見問題](#id2) 目錄 - [設計和歷史常見問題](#design-and-history-faq) - [為什么Python使用縮進來分組語句?](#why-does-python-use-indentation-for-grouping-of-statements) - [為什么簡單的算術運算得到奇怪的結果?](#why-am-i-getting-strange-results-with-simple-arithmetic-operations) - [為什么浮點計算不準確?](#why-are-floating-point-calculations-so-inaccurate) - [為什么Python字符串是不可變的?](#why-are-python-strings-immutable) - [為什么必須在方法定義和調用中顯式使用“self”?](#why-must-self-be-used-explicitly-in-method-definitions-and-calls) - [為什么不能在表達式中賦值?](#why-can-t-i-use-an-assignment-in-an-expression) - [為什么Python對某些功能(例如list.index())使用方法來實現,而其他功能(例如len(List))使用函數實現?](#why-does-python-use-methods-for-some-functionality-e-g-list-index-but-functions-for-other-e-g-len-list) - [為什么 join()是一個字符串方法而不是列表或元組方法?](#why-is-join-a-string-method-instead-of-a-list-or-tuple-method) - [異常有多快?](#how-fast-are-exceptions) - [為什么Python中沒有switch或case語句?](#why-isn-t-there-a-switch-or-case-statement-in-python) - [難道不能在解釋器中模擬線程,而非得依賴特定于操作系統的線程實現嗎?](#can-t-you-emulate-threads-in-the-interpreter-instead-of-relying-on-an-os-specific-thread-implementation) - [為什么lambda表達式不能包含語句?](#why-can-t-lambda-expressions-contain-statements) - [可以將Python編譯為機器代碼,C或其他語言嗎?](#can-python-be-compiled-to-machine-code-c-or-some-other-language) - [Python如何管理內存?](#how-does-python-manage-memory) - [為什么CPython不使用更傳統的垃圾回收方案?](#why-doesn-t-cpython-use-a-more-traditional-garbage-collection-scheme) - [CPython退出時為什么不釋放所有內存?](#why-isn-t-all-memory-freed-when-cpython-exits) - [為什么有單獨的元組和列表數據類型?](#why-are-there-separate-tuple-and-list-data-types) - [列表是如何在CPython中實現的?](#how-are-lists-implemented-in-cpython) - [字典是如何在CPython中實現的?](#how-are-dictionaries-implemented-in-cpython) - [為什么字典key必須是不可變的?](#why-must-dictionary-keys-be-immutable) - [為什么 list.sort() 沒有返回排序列表?](#why-doesn-t-list-sort-return-the-sorted-list) - [如何在Python中指定和實施接口規范?](#how-do-you-specify-and-enforce-an-interface-spec-in-python) - [為什么沒有goto?](#why-is-there-no-goto) - [為什么原始字符串(r-strings)不能以反斜杠結尾?](#why-can-t-raw-strings-r-strings-end-with-a-backslash) - [為什么Python沒有屬性賦值的“with”語句?](#why-doesn-t-python-have-a-with-statement-for-attribute-assignments) - [為什么 if/while/def/class語句需要冒號?](#why-are-colons-required-for-the-if-while-def-class-statements) - [為什么Python在列表和元組的末尾允許使用逗號?](#why-does-python-allow-commas-at-the-end-of-lists-and-tuples) ## [為什么Python使用縮進來分組語句?](#id3) Guido van Rossum 認為使用縮進進行分組非常優雅,并且大大提高了普通Python程序的清晰度。大多數人在一段時間后就學會并喜歡上這個功能。 由于沒有開始/結束括號,因此解析器感知的分組與人類讀者之間不會存在分歧。偶爾C程序員會遇到像這樣的代碼片段: ``` if (x <= y) x++; y--; z++; ``` 如果條件為真,則只執行 `x++` 語句,但縮進會使你認為情況并非如此。即使是經驗豐富的C程序員有時會長時間盯著它,想知道為什么即使 `x > y` , `y` 也在減少。 因為沒有開始/結束括號,所以Python不太容易發生編碼式沖突。在C中,括號可以放到許多不同的位置。如果您習慣于閱讀和編寫使用一種風格的代碼,那么在閱讀(或被要求編寫)另一種風格時,您至少會感到有些不安。 許多編碼風格將開始/結束括號單獨放在一行上。這使得程序相當長,浪費了寶貴的屏幕空間,使得更難以對程序進行全面的了解。理想情況下,函數應該適合一個屏幕(例如,20--30行)。 20行Python可以完成比20行C更多的工作。這不僅僅是由于缺少開始/結束括號 -- 缺少聲明和高級數據類型也是其中的原因 -- 但縮進基于語法肯定有幫助。 ## [為什么簡單的算術運算得到奇怪的結果?](#id4) 請看下一個問題。 ## [為什么浮點計算不準確?](#id5) 用戶經常對這樣的結果感到驚訝: ``` >>> 1.2 - 1.0 0.19999999999999996 ``` 并且認為這是 Python中的一個 bug。其實不是這樣。這與 Python 關系不大,而與底層平臺如何處理浮點數字關系更大。 CPython 中的 [`float`](../library/functions.xhtml#float "float") 類型使用C語言的 `double` 類型進行存儲。 [`float`](../library/functions.xhtml#float "float") 對象的值是以固定的精度(通常為 53 位)存儲的二進制浮點數,由于 Python 使用 C 操作,而后者依賴于處理器中的硬件實現來執行浮點運算。 這意味著就浮點運算而言,Python 的行為類似于許多流行的語言,包括 C 和 Java。 許多可以輕松地用十進制表示的數字不能用二進制浮點表示。例如,之后: ``` >>> x = 1.2 ``` 為 `x` 存儲的值是與十進制的值 `1.2` (非常接近) 的近似值,但不完全等于它。 在典型的機器上,實際存儲的值是: ``` 1.0011001100110011001100110011001100110011001100110011 (binary) ``` 確切地說: ``` 1.1999999999999999555910790149937383830547332763671875 (decimal) ``` 典型的 53 位精度為 Python 浮點數提供了 15-16 位小數的精度。 要獲得更完整的解釋,請參閱 Python 教程中的 [浮點算術](../tutorial/floatingpoint.xhtml#tut-fp-issues) 一章。 ## [為什么Python字符串是不可變的?](#id6) 有幾個優點。 一個是性能:知道字符串是不可變的,意味著我們可以在創建時為它分配空間,并且存儲需求是固定不變的。這也是元組和列表之間區別的原因之一。 另一個優點是,Python 中的字符串被視為與數字一樣“基本”。 任何動作都不會將值 8 更改為其他值,在 Python 中,任何動作都不會將字符串 "8" 更改為其他值。 ## [為什么必須在方法定義和調用中顯式使用“self”?](#id7) 這個想法借鑒了 Modula-3 語言。 出于多種原因它被證明是非常有用的。 首先,更明顯的顯示出,使用的是方法或實例屬性而不是局部變量。 閱讀 `self.x` 或 `self.meth()` 可以清楚地表明,即使您不知道類的定義,也會使用實例變量或方法。在 C++ 中,可以通過缺少局部變量聲明來判斷(假設全局變量很少見或容易識別) —— 但是在 Python 中沒有局部變量聲明,所以必須查找類定義才能確定。 一些 C++ 和 Java 編碼標準要求實例屬性具有 `m_` 前綴,因此這種顯式性在這些語言中仍然有用。 其次,這意味著如果要顯式引用或從特定類調用該方法,不需要特殊語法。 在 C++ 中,如果你想使用在派生類中重寫基類中的方法,你必須使用 `::` 運算符 -- 在 Python 中你可以編寫 `baseclass.methodname(self, <argument list>)`。 這對于 [`__init__()`](../reference/datamodel.xhtml#object.__init__ "object.__init__") 方法非常有用,特別是在派生類方法想要擴展同名的基類方法,而必須以某種方式調用基類方法時。 最后,它解決了變量賦值的語法問題:為了 Python 中的局部變量(根據定義!)在函數體中賦值的那些變量(并且沒有明確聲明為全局)賦值,就必須以某種方式告訴解釋器一個賦值是為了分配一個實例變量而不是一個局部變量,它最好是通過語法實現的(出于效率原因)。 C++ 通過聲明來做到這一點,但是 Python 沒有聲明,僅僅為了這個目的而引入它們會很可惜。 使用顯式的 `self.var` 很好地解決了這個問題。 類似地,對于使用實例變量,必須編寫 `self.var` 意味著對方法內部的非限定名稱的引用不必搜索實例的目錄。 換句話說,局部變量和實例變量存在于兩個不同的命名空間中,您需要告訴 Python 使用哪個命名空間。 ## [為什么不能在表達式中賦值?](#id8) 許多習慣于C或Perl的人抱怨,他們想要使用C 的這個特性: ``` while (line = readline(f)) { // do something with line } ``` 但在Python中被強制寫成這樣: ``` while True: line = f.readline() if not line: break ... # do something with line ``` 不允許在 Python 表達式中賦值的原因是這些其他語言中常見的、很難發現的錯誤,是由這個結構引起的: ``` if (x = 0) { // error handling } else { // code that only works for nonzero x } ``` 錯誤是一個簡單的錯字: `x = 0` ,將0賦給變量 `x` ,而比較 `x == 0` 肯定是可以預期的。 已經有許多替代方案提案。 大多數是為了少打一些字的黑客方案,但使用任意或隱含的語法或關鍵詞,并不符合語言變更提案的簡單標準:它應該直觀地向尚未被介紹到這一概念的人類讀者提供正確的含義。 一個有趣的現象是,大多數有經驗的Python程序員都認識到 `while True` 的習慣用法,也不太在意是否能在表達式構造中賦值; 只有新人表達了強烈的愿望希望將其添加到語言中。 有一種替代的拼寫方式看起來很有吸引力,但通常不如"while True"解決方案可靠: ``` line = f.readline() while line: ... # do something with line... line = f.readline() ``` 問題在于,如果你改變主意(例如你想把它改成 `sys.stdin.readline()` ),如何知道下一行。你必須記住改變程序中的兩個地方 -- 第二次出現隱藏在循環的底部。 最好的方法是使用迭代器,這樣能通過 `for` 語句來循環遍歷對象。例如 [file objects](../glossary.xhtml#term-file-object) 支持迭代器協議,因此可以簡單地寫成: ``` for line in f: ... # do something with line... ``` ## [為什么Python對某些功能(例如list.index())使用方法來實現,而其他功能(例如len(List))使用函數實現?](#id9) 正如Guido所說: > (a) 對于某些操作,前綴表示法比后綴更容易閱讀 -- 前綴(和中綴!)運算在數學中有著悠久的傳統,就像在視覺上幫助數學家思考問題的記法。比較一下我們將 x\*(a+b) 這樣的公式改寫為 x\*a+x\*b 的容易程度,以及使用原始OO符號做相同事情的笨拙程度。 > > (b) 當讀到寫有len(X)的代碼時,就知道它要求的是某件東西的長度。這告訴我們兩件事:結果是一個整數,參數是某種容器。相反,當閱讀x.len()時,必須已經知道x是某種實現接口的容器,或者是從具有標準len()的類繼承的容器。當沒有實現映射的類有get()或key()方法,或者不是文件的類有write()方法時,我們偶爾會感到困惑。 > > —<https://mail.python.org/pipermail/python-3000/2006-November/004643.html> ## [為什么 join()是一個字符串方法而不是列表或元組方法?](#id10) 從Python 1.6開始,字符串變得更像其他標準類型,當添加方法時,這些方法提供的功能與始終使用String模塊的函數時提供的功能相同。這些新方法中的大多數已被廣泛接受,但似乎讓一些程序員感到不舒服的一種方法是: ``` ", ".join(['1', '2', '4', '8', '16']) ``` 結果如下: ``` "1, 2, 4, 8, 16" ``` 反對這種用法有兩個常見的論點。 第一條是這樣的:“使用字符串文本(String Constant)的方法看起來真的很難看”,答案是也許吧,但是字符串文本只是一個固定值。如果在綁定到字符串的名稱上允許使用這些方法,則沒有邏輯上的理由使其在文字上不可用。 第二個異議通常是這樣的:“我實際上是在告訴序列使用字符串常量將其成員連接在一起”。遺憾的是并非如此。出于某種原因,把 [`split()`](../library/stdtypes.xhtml#str.split "str.split") 作為一個字符串方法似乎要容易得多,因為在這種情況下,很容易看到: ``` "1, 2, 4, 8, 16".split(", ") ``` 是對字符串文本的指令,用于返回由給定分隔符分隔的子字符串(或在默認情況下,返回任意空格)。 [`join()`](../library/stdtypes.xhtml#str.join "str.join") 是字符串方法,因為在使用該方法時,您告訴分隔符字符串去迭代一個字符串序列,并在相鄰元素之間插入自身。此方法的參數可以是任何遵循序列規則的對象,包括您自己定義的任何新的類。對于字節和字節數組對象也有類似的方法。 ## [異常有多快?](#id11) 如果沒有引發異常,則try/except塊的效率極高。實際上捕獲異常是昂貴的。在2.0之前的Python版本中,通常使用這個習慣用法: ``` try: value = mydict[key] except KeyError: mydict[key] = getvalue(key) value = mydict[key] ``` 只有當你期望dict在任何時候都有key時,這才有意義。如果不是這樣的話,你就是應該這樣編碼: ``` if key in mydict: value = mydict[key] else: value = mydict[key] = getvalue(key) ``` 對于這種特定的情況,您還可以使用 `value = dict.setdefault(key, getvalue(key))`,但前提是調用 `getvalue()` 足夠便宜,因為在所有情況下都會對其進行評估。 ## [為什么Python中沒有switch或case語句?](#id12) 你可以通過一系列 `if... elif... elif... else`.輕松完成這項工作。對于switch語句語法已經有了一些建議,但尚未就是否以及如何進行范圍測試達成共識。有關完整的詳細信息和當前狀態,請參閱 [**PEP 275**](https://www.python.org/dev/peps/pep-0275) \[https://www.python.org/dev/peps/pep-0275\] 。 對于需要從大量可能性中進行選擇的情況,可以創建一個字典,將case 值映射到要調用的函數。例如: ``` def function_1(...): ... functions = {'a': function_1, 'b': function_2, 'c': self.method_1, ...} func = functions[value] func() ``` 對于對象調用方法,可以通過使用 [`getattr()`](../library/functions.xhtml#getattr "getattr") 內置檢索具有特定名稱的方法來進一步簡化: ``` def visit_a(self, ...): ... ... def dispatch(self, value): method_name = 'visit_' + str(value) method = getattr(self, method_name) method() ``` 建議對方法名使用前綴,例如本例中的 `visit_` 。如果沒有這樣的前綴,如果值來自不受信任的源,攻擊者將能夠調用對象上的任何方法。 ## [難道不能在解釋器中模擬線程,而非得依賴特定于操作系統的線程實現嗎?](#id13) 答案1: 不幸的是,解釋器為每個Python堆棧幀推送至少一個C堆棧幀。此外,擴展可以隨時回調Python。因此,一個完整的線程實現需要對C的線程支持。 答案2: 幸運的是, [Stackless Python](https://github.com/stackless-dev/stackless/wiki) \[https://github.com/stackless-dev/stackless/wiki\] 有一個完全重新設計的解釋器循環,可以避免C堆棧。 ## [為什么lambda表達式不能包含語句?](#id14) Python的 lambda表達式不能包含語句,因為Python的語法框架不能處理嵌套在表達式內部的語句。然而,在Python中,這并不是一個嚴重的問題。與其他語言中添加功能的lambda表單不同,Python的 lambdas只是一種速記符號,如果您懶得定義函數的話。 函數已經是Python中的第一類對象,可以在本地范圍內聲明。 因此,使用lambda而不是本地定義的函數的唯一優點是你不需要為函數創建一個名稱 -- 這只是一個分配了函數對象(與lambda表達式生成的對象類型完全相同)的局部變量! ## [可以將Python編譯為機器代碼,C或其他語言嗎?](#id15) [Cython](http://cython.org/) \[http://cython.org/\] 將帶有可選注釋的Python修改版本編譯到C擴展中。 [Nuitka](http://www.nuitka.net/) \[http://www.nuitka.net/\] 是一個將Python編譯成 C++ 代碼的新興編譯器,旨在支持完整的Python語言。要編譯成Java,可以考慮 [VOC](https://voc.readthedocs.io) \[https://voc.readthedocs.io\] 。 ## [Python如何管理內存?](#id16) Python 內存管理的細節取決于實現。 Python 的標準實現 [CPython](../glossary.xhtml#term-cpython) 使用引用計數來檢測不可訪問的對象,并使用另一種機制來收集引用循環,定期執行循環檢測算法來查找不可訪問的循環并刪除所涉及的對象。 [`gc`](../library/gc.xhtml#module-gc "gc: Interface to the cycle-detecting garbage collector.") 模塊提供了執行垃圾回收、獲取調試統計信息和優化收集器參數的函數。 但是,其他實現(如 [Jython](http://www.jython.org) \[http://www.jython.org\] 或 [PyPy](http://www.pypy.org) \[http://www.pypy.org\] ),)可以依賴不同的機制,如完全的垃圾回收器 。如果你的Python代碼依賴于引用計數實現的行為,則這種差異可能會導致一些微妙的移植問題。 在一些Python實現中,以下代碼(在CPython中工作的很好)可能會耗盡文件描述符: ``` for file in very_long_list_of_files: f = open(file) c = f.read(1) ``` 實際上,使用CPython的引用計數和析構函數方案, 每個新賦值的 *f* 都會關閉前一個文件。然而,對于傳統的GC,這些文件對象只能以不同的時間間隔(可能很長的時間間隔)被收集(和關閉)。 如果要編寫可用于任何python實現的代碼,則應顯式關閉該文件或使用 [`with`](../reference/compound_stmts.xhtml#with) 語句;無論內存管理方案如何,這都有效: ``` for file in very_long_list_of_files: with open(file) as f: c = f.read(1) ``` ## [為什么CPython不使用更傳統的垃圾回收方案?](#id17) 首先,這不是C標準特性,因此不能移植。(是的,我們知道Boehm GC庫。它包含了 *大多數* 常見平臺(但不是所有平臺)的匯編代碼,盡管它基本上是透明的,但也不是完全透明的; 要讓Python使用它,需要使用補丁。) 當Python嵌入到其他應用程序中時,傳統的GC也成為一個問題。在獨立的Python中,可以用GC庫提供的版本替換標準的malloc()和free(),嵌入Python的應用程序可能希望用 *它自己* 替代malloc()和free(),而可能不需要Python的。現在,CPython可以正確地實現malloc()和free()。 ## [CPython退出時為什么不釋放所有內存?](#id18) 當Python退出時,從全局命名空間或Python模塊引用的對象并不總是被釋放。 如果存在循環引用,則可能發生這種情況 C庫分配的某些內存也是不可能釋放的(例如像Purify這樣的工具會抱怨這些內容)。 但是,Python在退出時清理內存并嘗試銷毀每個對象。 如果要強制 Python 在釋放時刪除某些內容,請使用 [`atexit`](../library/atexit.xhtml#module-atexit "atexit: Register and execute cleanup functions.") 模塊運行一個函數,強制刪除這些內容。 ## [為什么有單獨的元組和列表數據類型?](#id19) 雖然列表和元組在許多方面是相似的,但它們的使用方式通常是完全不同的。可以認為元組類似于Pascal記錄或C結構;它們是相關數據的小集合,可以是不同類型的數據,可以作為一個組進行操作。例如,笛卡爾坐標適當地表示為兩個或三個數字的元組。 另一方面,列表更像其他語言中的數組。它們傾向于持有不同數量的對象,所有對象都具有相同的類型,并且逐個操作。例如, `os.listdir('.')` 返回表示當前目錄中的文件的字符串列表。如果向目錄中添加了一兩個文件,對此輸出進行操作的函數通常不會中斷。 元組是不可變的,這意味著一旦創建了元組,就不能用新值替換它的任何元素。列表是可變的,這意味著您始終可以更改列表的元素。只有不變元素可以用作字典的key,因此只能將元組和非列表用作key。 ## [列表是如何在CPython中實現的?](#id20) CPython的列表實際上是可變長度的數組,而不是lisp風格的鏈表。該實現使用對其他對象的引用的連續數組,并在列表頭結構中保留指向該數組和數組長度的指針。 這使得索引列表 `a[i]` 的操作成本與列表的大小或索引的值無關。 當添加或插入項時,將調整引用數組的大小。并采用了一些巧妙的方法來提高重復添加項的性能; 當數組必須增長時,會分配一些額外的空間,以便在接下來的幾次中不需要實際調整大小。 ## [字典是如何在CPython中實現的?](#id21) CPython的字典實現為可調整大小的哈希表。與B-樹相比,這在大多數情況下為查找(目前最常見的操作)提供了更好的性能,并且實現更簡單。 字典的工作方式是使用 [`hash()`](../library/functions.xhtml#hash "hash") 內置函數計算字典中存儲的每個鍵的hash代碼。hash代碼根據鍵和每個進程的種子而變化很大;例如,"Python" 的hash值為-539294296,而"python"(一個按位不同的字符串)的hash值為1142331976。然后,hash代碼用于計算內部數組中將存儲該值的位置。假設您存儲的鍵都具有不同的hash值,這意味著字典需要恒定的時間 -- O(1),用Big-O表示法 -- 來檢索一個鍵。 ## [為什么字典key必須是不可變的?](#id22) 字典的哈希表實現使用從鍵值計算的哈希值來查找鍵。如果鍵是可變對象,則其值可能會發生變化,因此其哈希值也會發生變化。但是,由于無論誰更改鍵對象都無法判斷它是否被用作字典鍵值,因此無法在字典中修改條目。然后,當你嘗試在字典中查找相同的對象時,將無法找到它,因為其哈希值不同。如果你嘗試查找舊值,也不會找到它,因為在該哈希表中找到的對象的值會有所不同。 如果你想要一個用列表索引的字典,只需先將列表轉換為元組;用函數 `tuple(L)` 創建一個元組,其條目與列表 `L` 相同。 元組是不可變的,因此可以用作字典鍵。 已經提出的一些不可接受的解決方案: - 哈希按其地址(對象ID)列出。這不起作用,因為如果你構造一個具有相同值的新列表,它將無法找到;例如: ``` mydict = {[1, 2]: '12'} print(mydict[[1, 2]]) ``` 會引發一個 [`KeyError`](../library/exceptions.xhtml#KeyError "KeyError") 異常,因為第二行中使用的 `[1, 2]` 的 id 與第一行中的 id 不同。換句話說,應該使用 `==` 來比較字典鍵,而不是使用 [`is`](../reference/expressions.xhtml#is) 。 - 使用列表作為鍵時進行復制。這沒有用的,因為作為可變對象的列表可以包含對自身的引用,然后復制代碼將進入無限循環。 - 允許列表作為鍵,但告訴用戶不要修改它們。當你意外忘記或修改列表時,這將產生程序中的一類難以跟蹤的錯誤。它還使一個重要的字典不變量無效: `d.keys()` 中的每個值都可用作字典的鍵。 - 將列表用作字典鍵后,應標記為其只讀。問題是,它不僅僅是可以改變其值的頂級對象;你可以使用包含列表作為鍵的元組。將任何內容作為鍵關聯到字典中都需要將從那里可到達的所有對象標記為只讀 —— 并且自引用對象可能會導致無限循環。 如果需要,可以使用以下方法來解決這個問題,但使用它需要你自擔風險:你可以將一個可變結構包裝在一個類實例中,該實例同時具有 [`__eq__()`](../reference/datamodel.xhtml#object.__eq__ "object.__eq__") 和 [`__hash__()`](../reference/datamodel.xhtml#object.__hash__ "object.__hash__") 方法。然后,你必須確保駐留在字典(或其他基于 hash 的結構)中的所有此類包裝器對象的哈希值在對象位于字典(或其他結構)中時保持固定。: ``` class ListWrapper: def __init__(self, the_list): self.the_list = the_list def __eq__(self, other): return self.the_list == other.the_list def __hash__(self): l = self.the_list result = 98767 - len(l)*555 for i, el in enumerate(l): try: result = result + (hash(el) % 9999999) * 1001 + i except Exception: result = (result % 7777777) + i * 333 return result ``` 注意,哈希計算由于列表的某些成員可能不可用以及算術溢出的可能性而變得復雜。 此外,必須始終如此,如果 `o1 == o2` (即 `o1.__eq__(o2) is True` )則 `hash(o1) == hash(o2)``(即 ``o1.__hash__() == o2.__hash__()` ),無論對象是否在字典中。 如果你不能滿足這些限制,字典和其他基于 hash 的結構將會出錯。 對于 ListWrapper ,只要包裝器對象在字典中,包裝列表就不能更改以避免異常。除非你準備好認真考慮需求以及不正確地滿足這些需求的后果,否則不要這樣做。請留意。 ## [為什么 list.sort() 沒有返回排序列表?](#id23) 在性能很重要的情況下,僅僅為了排序而復制一份列表將是一種浪費。因此, [`list.sort()`](../library/stdtypes.xhtml#list.sort "list.sort") 對列表進行了適當的排序。為了提醒您這一事實,它不會返回已排序的列表。這樣,當您需要排序的副本,但也需要保留未排序的版本時,就不會意外地覆蓋列表。 如果要返回新列表,請使用內置 [`sorted()`](../library/functions.xhtml#sorted "sorted") 函數。此函數從提供的可迭代列表中創建新列表,對其進行排序并返回。例如,下面是如何迭代遍歷字典并按keys排序: ``` for key in sorted(mydict): ... # do whatever with mydict[key]... ``` ## [如何在Python中指定和實施接口規范?](#id24) 由C++和Java等語言提供的模塊接口規范描述了模塊的方法和函數的原型。許多人認為接口規范的編譯時強制執行有助于構建大型程序。 Python 2.6添加了一個 [`abc`](../library/abc.xhtml#module-abc "abc: Abstract base classes according to PEP 3119.") 模塊,允許定義抽象基類 (ABCs)。然后可以使用 [`isinstance()`](../library/functions.xhtml#isinstance "isinstance") 和 [`issubclass()`](../library/functions.xhtml#issubclass "issubclass") 來檢查實例或類是否實現了特定的ABC。 [`collections.abc`](../library/collections.abc.xhtml#module-collections.abc "collections.abc: Abstract base classes for containers") 模塊定義了一組有用的ABCs 例如 [`Iterable`](../library/collections.abc.xhtml#collections.abc.Iterable "collections.abc.Iterable") , [`Container`](../library/collections.abc.xhtml#collections.abc.Container "collections.abc.Container") , 和 [`MutableMapping`](../library/collections.abc.xhtml#collections.abc.MutableMapping "collections.abc.MutableMapping") 對于Python,通過對組件進行適當的測試規程,可以獲得接口規范的許多好處。還有一個工具PyChecker,可用于查找由于子類化引起的問題。 一個好的模塊測試套件既可以提供回歸測試,也可以作為模塊接口規范和一組示例。許多Python模塊可以作為腳本運行,以提供簡單的“自我測試”。即使是使用復雜外部接口的模塊,也常常可以使用外部接口的簡單“樁代碼(stub)”模擬進行隔離測試。可以使用 [`doctest`](../library/doctest.xhtml#module-doctest "doctest: Test pieces of code within docstrings.") 和 [`unittest`](../library/unittest.xhtml#module-unittest "unittest: Unit testing framework for Python.") 模塊或第三方測試框架來構造詳盡的測試套件,以運行模塊中的每一行代碼。 適當的測試規程可以幫助在Python中構建大型的、復雜的應用程序以及接口規范。事實上,它可能會更好,因為接口規范不能測試程序的某些屬性。例如, `append()` 方法將向一些內部列表的末尾添加新元素;接口規范不能測試您的 `append()` 實現是否能夠正確執行此操作,但是在測試套件中檢查這個屬性是很簡單的。 編寫測試套件非常有用,您可能希望設計代碼時著眼于使其易于測試。一種日益流行的技術是面向測試的開發,它要求在編寫任何實際代碼之前,首先編寫測試套件的各個部分。當然,Python允許您草率行事,根本不編寫測試用例。 ## [為什么沒有goto?](#id25) 可以使用異常捕獲來提供 “goto結構” ,甚至可以跨函數調用工作的 。許多人認為異常捕獲可以方便地模擬C,Fortran和其他語言的 "go" 或 "goto" 結構的所有合理用法。例如: ``` class label(Exception): pass # declare a label try: ... if condition: raise label() # goto label ... except label: # where to goto pass ... ``` 但是不允許你跳到循環的中間,這通常被認為是濫用goto。謹慎使用。 ## [為什么原始字符串(r-strings)不能以反斜杠結尾?](#id26) 更準確地說,它們不能以奇數個反斜杠結束:結尾處的不成對反斜杠會轉義結束引號字符,留下未結束的字符串。 原始字符串的設計是為了方便想要執行自己的反斜杠轉義處理的處理器(主要是正則表達式引擎)創建輸入。此類處理器將不匹配的尾隨反斜杠視為錯誤,因此原始字符串不允許這樣做。反過來,允許通過使用引號字符轉義反斜杠轉義字符串。當r-string用于它們的預期目的時,這些規則工作的很好。 如果您正在嘗試構建Windows路徑名,請注意所有Windows系統調用都使用正斜杠: ``` f = open("/mydir/file.txt") # works fine! ``` 如果您正在嘗試為DOS命令構建路徑名,請嘗試以下示例 ``` dir = r"\this\is\my\dos\dir" "\\" dir = r"\this\is\my\dos\dir\ "[:-1] dir = "\\this\\is\\my\\dos\\dir\\" ``` ## [為什么Python沒有屬性賦值的“with”語句?](#id27) Python有一個 'with' 語句,它封裝了塊的執行,在塊的入口和出口調用代碼。有些語言的結構是這樣的: ``` with obj: a = 1 # equivalent to obj.a = 1 total = total + 1 # obj.total = obj.total + 1 ``` 在Python中,這樣的結構是不明確的。 其他語言,如ObjectPascal、Delphi和C++ 使用靜態類型,因此可以毫不含糊地知道分配給什么成員。這是靜態類型的要點 -- 編譯器 *總是* 在編譯時知道每個變量的作用域。 Python使用動態類型。事先不可能知道在運行時引用哪個屬性。可以動態地在對象中添加或刪除成員屬性。這使得無法通過簡單的閱讀就知道引用的是什么屬性:局部屬性、全局屬性還是成員屬性? 例如,采用以下不完整的代碼段: ``` def foo(a): with a: print(x) ``` 該代碼段假設 "a" 必須有一個名為 "x" 的成員屬性。然而,Python中并沒有告訴解釋器這一點。假設 "a" 是整數,會發生什么?如果有一個名為 "x" 的全局變量,它是否會在with塊中使用?如您所見,Python的動態特性使得這樣的選擇更加困難。 然而,Python 可以通過賦值輕松實現 "with" 和類似語言特性(減少代碼量)的主要好處。代替: ``` function(args).mydict[index][index].a = 21 function(args).mydict[index][index].b = 42 function(args).mydict[index][index].c = 63 ``` 寫成這樣: ``` ref = function(args).mydict[index][index] ref.a = 21 ref.b = 42 ref.c = 63 ``` 這也具有提高執行速度的副作用,因為Python在運行時解析名稱綁定,而第二個版本只需要執行一次解析。 ## [為什么 if/while/def/class語句需要冒號?](#id28) 冒號主要用于增強可讀性(ABC語言實驗的結果之一)。考慮一下這個: ``` if a == b print(a) ``` 與 ``` if a == b: print(a) ``` 注意第二種方法稍微容易一些。請進一步注意,在這個FAQ解答的示例中,冒號是如何設置的;這是英語中的標準用法。 另一個次要原因是冒號使帶有語法突出顯示的編輯器更容易工作;他們可以尋找冒號來決定何時需要增加縮進,而不必對程序文本進行更精細的解析。 ## [為什么Python在列表和元組的末尾允許使用逗號?](#id29) Python 允許您在列表,元組和字典的末尾添加一個尾隨逗號: ``` [1, 2, 3,] ('a', 'b', 'c',) d = { "A": [1, 5], "B": [6, 7], # last trailing comma is optional but good style } ``` 有幾個理由允許這樣做。 如果列表,元組或字典的字面值分布在多行中,則更容易添加更多元素,因為不必記住在上一行中添加逗號。這些行也可以重新排序,而不會產生語法錯誤。 不小心省略逗號會導致難以診斷的錯誤。例如: ``` x = [ "fee", "fie" "foo", "fum" ] ``` 這個列表看起來有四個元素,但實際上包含三個 : "fee", "fiefoo" 和 "fum" 。總是加上逗號可以避免這個錯誤的來源。 允許尾隨逗號也可以使編程代碼更容易生成。 ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](library.xhtml "代碼庫和插件 FAQ") | - [上一頁](programming.xhtml "編程常見問題") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 常見問題](index.xhtml) ? - $('.inline-search').show(0); | ? [版權所有](../copyright.xhtml) 2001-2019, Python Software Foundation. Python 軟件基金會是一個非盈利組織。 [請捐助。](https://www.python.org/psf/donations/) 最后更新于 5月 21, 2019. [發現了問題](../bugs.xhtml)? 使用[Sphinx](http://sphinx.pocoo.org/)1.8.4 創建。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看