Java vs Python:Java 開發人員的基本 Python

      網友投稿 849 2025-04-04

      目錄


      Python 來自哪里?

      Python 的 Philosophy 是什么?

      Python 代碼可讀

      Python Comes With Batteries Included

      Python 促進代碼重用

      Python 易于擴展

      如何開始發現 Python?

      安裝 Python

      創建沙箱并使用它

      選擇編輯器或集成開發環境

      Python 與 Java 有何不同?

      代碼塊分組的縮進

      從頭開始的讀取-評估-打印循環

      動態類型和強類型

      CPython 與 JIT 編譯器

      內置函數和運算符重載

      集合函數處理的好語法

      萬物皆對象

      Java 和 Python 的哪些方面相似?

      基于類的面向對象

      Operators

      字符串格式

      控制流結構

      Java 與 Python:什么是高級本機數據類型?

      Numeric Types and Their Operators

      基本序列類型

      字典

      Sets

      字符串

      字節

      布爾值

      None

      More Container Data Types

      有哪些特定用途的資源?

      Python 何時會比 Java 更有用,為什么?

      結論

      其他資源

      Python 是一種通用的編程語言。您可以通過考慮其學習的平易性及其對數據分析、機器學習和 Web 開發的高度適用性來了解它在過去幾年中的增長。但它是一種什么樣的編程語言?比較 Java 與 Python 時有哪些區別?你能用它做什么?它真的像某些人聲稱的那樣“容易學習”嗎?

      在本教程中,您將從 Java 的角度探索 Python。閱讀之后,您將能夠決定 Python 是否是解決您的用例的可行選擇,并能夠欣賞何時可以將 Python 與 Java 結合使用來解決某些類型的問題。

      在本教程中,您將了解:

      Python 編程語言的通用語法

      最相關的標準數據類型

      的差異和相似之處VS Python的Java中

      高質量 Python文檔和教程的資源

      一些 Python 社區最喜歡的框架和庫

      從頭開始Python 編程的方法

      本教程適用于熟悉 Java 的內部工作原理、概念、術語、類、類型、集合框架等的軟件開發人員。

      您根本不需要任何 Python 經驗。

      Python 來自哪里?

      Python 是由Guido van Rossum開發的一種編程語言。1989 年,他正在尋找一個可以讓他在 1989 年圣誕節假期里忙得不可開交的業余編程項目,于是他開始開發 Python 解釋器。

      Python 起源于多種語言:ABC、C和Modula-3。它基本上是一種面向對象的命令式編程語言。

      根據您的偏好和所需的功能,它可以應用于完全面向對象的風格或具有函數的過程編程風格。本教程稍后將介紹面向對象的功能。

      注意:為了清楚起見,從 Java 的角度來看,Python 函數類似于靜態方法,您不一定需要在類中定義它們。稍后,您將看到 Python 函數定義的示例。

      此外,更函數式的編程風格也是完全可能的。要了解更多信息,您需要探索Python 的函數式編程能力。

      2021 年初,TIOBE第四次宣布 Python 為年度編程語言。截至 2021?Octoverse 報告,Python 被存儲庫貢獻者列為 GitHub 上第二大最受歡迎的語言。

      Python 的哲學是什么?

      很快,您將在本部分之后的部分中動手操作 Python?。但是,首先,您將通過了解一些可以追溯到 Python 哲學的特性來探索為什么值得更好地了解 Python。

      Java 和 Python 背后的一些想法是相似的,但每種編程語言都有其獨特的特征。Python 的哲學被捕獲為 19 條指導原則的集合,Python之禪。Python 隱藏了一些復活節彩蛋,其中之一是 Python 之禪。考慮在 Python?read-eval-print loop (REPL) 中發出以下命令時會發生什么:

      >>>

      >>> import this The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!

      雖然您不應該從字面上理解上面的陳述,但其中一些與您接下來要介紹的特征直接相關。

      注意:?Python read-eval-print 循環將在本教程的后面部分進行解釋。

      通過考慮 Python Zen of Python 的指導原則,您將對如何使用該語言有一個很好的了解。

      Python 代碼可讀

      如果您具有 Java 背景并且查看 Python 代碼的典型片段,您可能會認為您正在查看偽代碼。有幾個因素會導致這種情況:

      縮進用于語句分組。這使得代碼塊更短并促進了統一的編碼風格。稍后您將找到有關此主題的更多信息。

      一些內置的高級數據結構,結合一組適度的運算符符號,使 Python 非常具有表現力。

      選擇使用異常作為處理錯誤的主要方式可以保持代碼整潔。

      Python 程序員更喜歡受這種概念啟發的編碼風格,即請求寬恕比許可 (EAFP) 更容易,而不是躍躍欲試(LBYL)概念。這種風格強調程序的正常、愉快的路徑,然后您將弄清楚如何處理任何異常。

      您可以在本教程以及其他鏈接資源中找到一些示例,說明這在實踐中的表現。

      Python?Comes With Batteries Included

      Python 的目標是您只需使用 Python 的標準發行版就可以解決大多數日常問題。為此,Python 包含了所謂的標準庫。就像Java 類庫一樣,它是一個廣泛的有用工具集合,包括常量、函數、類和框架。

      要進一步了解 Python 標準庫,請查看Python 文檔的Python 教程中標準庫簡介的第一部分和第二部分。

      Python 促進代碼重用

      Python 提供了多種功能,使您能夠開發可以在不同地方重用的代碼,以應用不要重復自己 (DRY)原則。

      一個特點是您通常將代碼分解為Python 中的模塊和包。但是請注意,Python 模塊和包不同于 Java 模塊和包。如果您想從 Python 開發人員的角度了解更多關于這些概念的信息,您可以閱讀Python 模塊和包。

      您可以在 Python 中使用的另一種技術是面向對象編程。您將在本教程的稍后部分對此進行探討。

      您還可以使用裝飾器來修改 Python 函數、類或方法。這是另一種技術,因此您只能對功能進行一次編程,之后就可以從您修飾的任何函數、類或方法中使用它。

      Python 易于擴展

      模塊和包的支持是使用新功能輕松擴展 Python 的要素之一。您還可以通過重載Python 標準運算符和函數來定義新的或改編的行為。甚至可以影響類的創建方式。

      擴展 Python 最直接的方法是用純 Python 編寫代碼。您還可以通過使用簡化的 Python 方言(稱為 Cython)或 C 或 C++ 中的綁定來定義模塊。

      如何開始發現 Python?

      在本教程中,您將找到一些示例,這些示例可能會鼓勵您探索某些事物或親自嘗試 Python 代碼片段。作為 Java 開發人員,您可能還記得熟悉 Java 和安裝第一個 Java 開發工具包的第一步。同樣,如果您想開始使用 Python,首先需要安裝它,然后創建一個沙箱,您可以在其中安全地進行實驗。

      已經有幾個教程解釋了如何執行此操作,因此接下來的小節將為您提供這些資源。

      安裝 Python

      第一步是安裝最新版本的 Python。為此,請遵循此Python 3 安裝和設置指南。

      另一個可以查找安裝說明的地方是官方 Python 下載頁面。

      注意:確保您安裝了最新版本的 Python。在撰寫本教程時,最新版本是3.10.x 系列的最新補丁版本。本教程中顯示的代碼片段應該都適用于此版本的 Python。

      許多 Python 開發人員為支持各種 Python 版本的庫做出了貢獻,他們通常更喜歡在不干擾正常 Python 工作的情況下試用 Python 的預發布版本。在這些情況下,在同一臺機器上訪問多個版本的 Python 會很方便。提供該功能的工具是pyenv,可與 Java 的jEnv相媲美。

      創建沙箱并使用它

      第二步,您應該設置一個虛擬環境,以便您可以安全地利用開源 Python 生態系統。本節說明您應該如何以及為什么要這樣做。

      盡管 Python 附帶了一個具有各種功能的廣泛標準庫,但還有更多功能以外部包的形式提供,其中絕大多數是開源的。在Python包索引,或PyPI中的簡稱,是主要的中央資料庫,收集和提供這些軟件包。您可以使用該pip命令安裝軟件包。但是,在您這樣做之前,請先閱讀接下來的兩段。

      為避免依賴版本沖突,您通常不應在項目之間共享全局或個人 Python 安裝。在實踐中,您會為每個項目或實驗沙箱提供一個虛擬環境。

      這樣,您的項目就可以相互獨立。這種方法還可以防止包之間的版本沖突。如果您想了解有關此過程的更多信息,則可以閱讀有關如何創建和激活虛擬環境的詳細信息。

      選擇編輯器或集成開發環境

      作為設置的最后一步,決定您要使用哪個編輯器或 IDE。如果您習慣了 IntelliJ,那么PyCharm似乎是合乎邏輯的選擇,因為它屬于同一產品線。另一個流行的編輯器是Visual Studio Code,但您也可以從許多其他選項中進行選擇。

      在您安裝 Python、了解如何將外部包安裝到虛擬環境中并選擇編輯器或 IDE 后,您可以開始嘗試該語言。當您通讀本教程的其余部分時,您會發現大量的實驗和練習機會。

      Python 與 Java 有何不同?

      通過查看最顯著差異的地方,您可以快速了解 Python 是哪種編程語言。在以下小節中,您將了解 Python 與 Java 不同的最重要方式。

      代碼塊分組的縮進

      也許 Python 最引人注目的特性是它的語法。特別是,您指定其函數、類、流控制構造和代碼塊的方式與您可能習慣的方式大不相同。在 Java 中,您用眾所周知的花括號 ({和})表示代碼塊。但是,在 Python 中,您可以通過縮進級別來指示代碼塊。下面是一個演示縮進如何確定代碼塊分組的示例:

      1def parity(number): 2 result = "odd" # Function body 3 if number % 2 == 0: 4 result = "even" # Body of if-block 5 return result # Not part of if-block 6 7for num in range(4): # Not part of function 8 print("Number", num, "is", parity(num)) # Body of for-loop 9print("This is not part of the loop") # Not part of for-loop

      該代碼顯示了一些新概念:

      第 1 行:該def語句開始定義一個名為的新函數parity(),該函數接受一個名為 的參數number。請注意,如果該def語句出現在類定義塊中,它將改為啟動一個方法定義。

      第 2 行:在 內parity(),函數體以縮進級別開始。第一個語句是將"odd"字符串分配給result變量。

      第 3 行:您可以在此處看到if語句的開頭。

      第 4 行:額外的縮進開始一個新塊。當if語句的條件表達式number % 2 == 0,計算結果為真時執行此塊。在示例中,它僅包含您分配"even"給result變量的一行。

      5號線:在DEDENT語言先于return聲明中的標記結束if語句及其相關的塊。

      第 7 行:同樣,您會看到for循環開始之前的 dedent?。因此,for循環開始于與函數定義塊在第一行的開始相同的縮進級別。它標志著函數定義塊的結束。

      第 8 行:您會在for循環中看到同樣的情況再次發生。第一個print()函數調用是for循環塊的一部分。

      第 9 行:第二個 dedentedprint()函數調用不是for循環塊的一部分。

      您可能已經注意到,:一行末尾的冒號 (?) 引入了一個新的代碼子塊,它應該縮進一級。當下一條語句再次縮進時,此代碼塊結束。

      一個代碼塊必須至少包含一個語句。一個空的代碼塊是不可能的。在極少數不需要任何語句的情況下,您可以使用passstatement,它什么都不做。

      最后,您可能還注意到可以使用井號 (?#) 進行注釋。

      上面的示例將產生以下輸出:

      Number 0 is even Number 1 is odd Number 2 is even Number 3 is odd This is not part of the loop

      盡管這種定義塊的方式乍一看似乎很奇怪,甚至可能會嚇到您,但經驗表明人們會比您現在想象的更早習慣它。

      有一個有用的 Python 代碼樣式指南,稱為PEP 8。它建議使用四個位置的縮進級別,使用空格。樣式指南不建議在源代碼文件中使用選項卡。原因是不同的編輯器和系統終端可能使用不一致的制表位位置,并為不同的用戶或不同的操作系統呈現不同的代碼。

      注意:風格指南是Python Enhancement Proposal 的一個例子,簡稱PEP。PEP 不僅包含提案,而且還反映了實現規范,因此您可以將 PEP 與 Java 的 JEP 和 JSR 的聯合進行比較。PEP 0列出了 PEP 的索引。

      您可以在 PEP 8 中找到很多有趣的信息,包括 Python命名約定。如果您仔細閱讀它們,您會發現它們與 Java 的略有不同。

      從頭開始的讀取-評估-打印循環

      從一開始,Python 就一直有一個內置的read-eval-print loop (REPL)。REPL 讀取盡可能短的完整語句、表達式或塊,將其編譯為字節碼,并對其進行評估。如果被評估的代碼返回一個對象而不是None對象,它會輸出這個對象的明確表示。您將在本教程的None?后面找到 的解釋。

      注意:您可以將 Python REPL 與Java 的 JShell (JEP 222) 進行比較,后者從 JDK 9 開始可用。

      下面的片段展示了 Python 的 REPL 是如何工作的:

      >>>

      >>> zero = int(0) >>> zero 0 >>> float(zero) 0.0 >>> complex(zero) 0j >>> bool(zero) False >>> str(zero) '0'

      如您所見,解釋器總是試圖明確地顯示結果表達式值。在上面的示例中,您可以看到integer、 floating point 、complex、Boolean和string值是如何以不同方式顯示的。

      Java 和 Python 之間的區別涉及賦值運算符 (?=)。使用單個等號的常規 Python 賦值是語句而不是表達式,它會產生一些值或對象。

      這解釋了為什么 REPL 不打印對變量的賦值zero:語句總是計算為None。賦值之后的行包含變量表達式zero,以指示 REPL 無論如何顯示結果變量。

      注意:?Python 3.8 引入了賦值表達式運算符 (?:=),也稱為walrus 運算符。它為變量賦值,但與常規賦值不同的是,它像在表達式中一樣計算變量。這類似于 Java 中的賦值運算符。但是請注意,它不能與常規賦值語句完全互換。它的范圍實際上是相當有限的。

      在 REPL 中,下劃線特殊變量 (?_) 保存最后一個表達式的值,前提是它不是None。以下片段顯示了如何使用此特殊變量:

      >>>

      >>> 2 + 2 4 >>> _ 4 >>> _ + 2 6 >>> some_var = _ + 1 >>> _ 6 >>> some_var 7

      在您指定的值7來some_var,特變_仍持有價值6。那是因為賦值語句的計算結果為None。

      動態類型和強類型

      編程語言的一個重要特征是語言解釋器或編譯器執行類型驗證的時間、方式和程度。

      Python 是一種動態類型語言。這意味著變量、函數參數和函數返回值的類型是在運行時而不是在編譯時檢查的,這與 Java 不同。

      Python 同時也是一種強類型語言:

      每個對象都有與之關聯的特定類型。

      不兼容的類型之間需要顯式轉換。

      在這里,您將探索 Python 如何在運行時檢查類型兼容性以及如何使類型兼容:

      >>>

      >>> 40 + "2" Traceback (most recent call last): File "", line 1, in TypeError: unsupported operand type(s) for +: 'int' and 'str' >>> 40 + int("2") # Add two numbers 42 >>> str(40) + "2" # Concatenate strings '402' >>> 40 * "2" # Repeat string "2" forty times '2222222222222222222222222222222222222222'

      您會注意到,您不能僅將整數值添加到字符串值中。這在運行時受到保護。當解釋器檢測到運行時錯誤時,它會生成一個異常。REPL 捕獲Exception實例并顯示導致錯誤表達式的回溯。

      要解決此問題,請將一種類型轉換為另一種類型。如果要將兩個對象作為數字相加,則可以使用int()構造函數將表示數字的字符串轉換為普通數字。如果您想將兩個對象連接為字符串,則可以使用str()構造函數將數字轉換為字符串。

      上面 Python 會話的最后一行顯示了另一個功能。通過將一個序列與一個數字相乘,您可以獲得原始序列的連接結果,并按給定數字重復。

      盡管 Python 是一種動態類型語言,但可以為代碼提供類型注釋。

      在運行時,Python 不會對這些注解做任何事情,只是讓它們可用于自省。但是,存在靜態類型檢查器工具,可以檢測類型聲明與類型注釋函數、類和變量的實際使用之間的不一致。

      注意:如上所述,Python 運行時使類型注釋可用于代碼自省。一些庫會使用此信息,例如FastAPI。

      類型注釋可幫助您在代碼開發周期的早期階段檢測錯誤。特別是在大型軟件項目中,它們可以幫助您使代碼更易于維護并使代碼庫保持良好狀態。您通常會調用靜態類型檢查器作為構建管道中驗證步驟的一部分。大多數 IDE 也使用類型注釋。

      CPython 與 JIT 編譯器

      與 Java 不同,Python 的參考實現沒有 JIT 編譯器。到目前為止,最常用的 Python 實現是CPython。這也是參考實現。CPython是一個用 C 編寫的編譯器和解釋器,幾乎可以在所有可以想象的平臺上使用。

      CPython分兩步加載一個名為module的源文件:

      編譯:首先,CPython讀取代碼并編譯成字節碼,字節碼是CPython字節碼解釋器可以執行的指令序列。在有限的范圍內,您可以將編譯階段與 Javajavac將.java文件編譯為文件的方式進行比較.class。

      執行:?CPython 字節碼解釋器——換句話說,CPython 的虛擬機 (VM)?——隨后從第一步開始執行字節碼。

      注意:與 Java 不同,您不能假設相同的 Python 字節碼可以與其他 Python 實現一起使用,甚至可以在同一 Python 實現的不同版本之間使用。但是,它有助于減少加載模塊所需的時間。

      在編譯的模塊是,如果可能的話,保存在高速緩存目錄中。

      不像主流的Java虛擬機的實現,CPython中并沒有在后來編譯成字節碼原生對象代碼。但是,還有其他不同的 Python 實現:

      Java 平臺有一個名為Jython的 Python 實現。它在 JVM 中運行,并且在 Java 和 Python 之間存在直接的互操作性。

      同樣,有一個名為IronPython的版本可以在 .NET 平臺上運行。

      有一個使用名為PyPy的即時 (JIT)編譯器的實現。平均而言,PyPy 比 CPython 快 4.2 倍。

      最后,GraalVM是一個支持多種編程語言的高性能運行時。它為相當新的 Python 版本提供實驗性支持。

      上面的列表并不詳盡。Python 站點包含替代實現和分發的列表。

      內置函數和運算符重載

      作為Java開發人員,你可能知道的長期超載的方法重載。雖然Python 中有一個動態等價物,它提供了一些類似的功能,但 Python 中還有另一種重載,您可能會發現它更有用。

      您可以為任何符合條件的 Python 內置函數和運算符定義自定義類的新行為。

      注意:在這種情況下,您可以將符合條件的函數和運算符視為允許您重載其行為的函數和運算符。

      Python 提供了一種可訪問的方式來實現函數和運算符重載。

      您可以通過在類中定義特殊命名的方法來嘗試此操作。此類方法的名稱以兩個下劃線開頭和結尾,例如.__len__()或.__add__()。具有這樣名稱的標識符稱為dunder,雙下劃線(?__) 的縮寫。

      當您使用存在相應 dunder 方法的對象調用符合條件的內置函數時,Python 會將行為委托給此方法。同樣,當您使用一個或多個操作數包含相應 dunder 方法的運算符時,Python 會將行為委托給該方法。

      例如,您可以定義.__len__()為內置len()函數提供行為。同樣,您可以定義.__add__()為加法運算符 (?+)提供行為。

      這個特性使得不僅可以將 Python 代碼的漂亮、富有表現力和簡潔的語法應用于標準對象,還可以應用于自定義對象。

      集合函數處理的好語法

      在Java中,你可能已經通過結合調用構造名單map(),filter()和lambda表達式。您可以在 Python 中使用相同的函數和技術執行相同的操作。使用這些結構并不總是會產生最易讀的代碼片段。

      Python 為列表和其他集合的這種基本功能操作提供了一種優雅的替代語法。您可以對列表使用列表理解,對其他集合使用其他類型的理解。如果您想更多地了解 Python 中的推導式,那么您可以探索何時使用列表推導式。

      萬物皆對象

      在 Java 中,并非所有東西都是對象,盡管事實上唯一可以放置代碼的地方是在 Java 類中。例如,Java 原語42不是對象。

      就像 Java 一樣,Python 也完全支持面向對象的編程風格。與 Java 不同的是,在 Python中一切都是對象。Python 對象的一些示例是:

      數值

      文檔字符串

      函數和方法

      模塊

      堆棧回溯

      字節編譯的代碼對象

      班級本身

      因為它們是對象,所以您可以將所有這些存儲在變量中,傳遞它們,并在運行時內省它們。

      注意:正如你在上面讀到的,類是對象。由于根據定義對象是類的實例,因此類也必須是某物的實例。

      事實上,這些是元類的實例。標準元類是type,但您可以創建替代元類,通常是通過派生自type來改變創建類的方式。

      元類與重載內置函數和運算符的能力相結合,是使 Python 成為多功能編程工具包的一部分。它們允許您創建自己的可編程的類和實例的附加或替代行為領域。

      Java 和 Python 的哪些方面相似?

      盡管存在差異,但您可能已經發現 Java 和 Python 之間的一些相似之處。這是因為 Python 和 Java 都受到 C 編程語言的啟發。在您繼續探索 Python 的過程中,您會發現與 Java 的更多相似之處。

      基于類的面向對象

      Python 是一種基于類的、面向對象的編程語言,這也是 Java 的主要特性之一。但是,這兩種語言的面向對象特性集不同,要足夠詳細地解決這些問題,需要專門的教程。

      幸運的是,您可以深入研究 Python 與 Java 中的面向對象編程,以大致了解 Java 和 Python 在面向對象編程構造方面的差異。您還可以查看Python 3 中面向對象編程的概述,以擴展您對該主題的了解。

      Operators

      您可能會注意到這些語言的共同遺產的一個方面是它們如何使用運算符。其中許多在兩種語言中具有相同的含義。

      首先,比較 Java 和 Python 中眾所周知的算術運算符。加法運算符 (?+)、減法運算符 (?-)、乘法運算符 (?*)、除法運算符 (?/) 和模運算符 (?%) 在兩種語言中的用途幾乎相同——除了類整數操作數上的除法運算符。

      這同樣適用于按位運算符:按位 OR 運算符 (?|)、按位 AND 運算符 (?&)、按位 XOR 運算符 (?^) 和一元按位非運算符 (?~),以及用于左移的按位移位運算符 (?<<) 和右移 (?>>)。

      您可以[]在 Python 中使用方括號語法 (?) 來訪問序列的元素,就像您可以使用 Java 的數組訪問一樣。

      后面關于數據類型的部分提供了有關這些和一些附加運算符的更多詳細信息。或者,如果您現在想了解更多關于它們的信息,您可以閱讀Python 中的運算符和表達式。

      字符串格式

      最初,Python 根據printfC 編程語言中函數系列的處理方式提供字符串格式化功能。這類似于 Java 的String.format().?在 Python 中,%運算符執行此功能。運算符的左側包含格式字符串,右側包含位置參數的元組或鍵控參數的字典。

      注意:您將在本教程后面看到更多關于元組和字典的內容。

      以下會話顯示了一些示例:

      >>>

      >>> "Hello, %s!" % "world" # %-style, single argument 'Hello, world!' >>> "The %s is %d." % ("answer", 42) # %-style, positional 'The answer is 42.' >>> "The %(word)s is %(value)d." \ ... % dict(word="answer", value=42) # %-style, key-based 'The answer is 42.'

      最近,Python 接受了其他格式化字符串的方法。一種是使用.format()字符串方法,其中替換字段用大括號 (?{}) 表示。這方面的一個例子是"The {word} is {value}.".format(word="answer", value=42)。

      從 Python 3.6 開始,您還可以使用格式化字符串文字,也稱為f-strings。假設您在范圍內有兩個名為word和 的變量value。在這種情況下,表達式f"The {word} is {value}."為您呈現與.format()上面示例相同的字符串。

      控制流結構

      比較 Java 與 Python 時,控制流結構是相似的。這意味著您可能直觀地識別出許多控制流結構。然而,在更詳細的層面上,也存在差異。

      Pythonwhile循環類似于 Java 的:

      while (word := input("Enter word: ")) != "END": print(word) print("READY")

      代碼片段逐行將標準輸入復制到標準輸出,直到該行等于"END"。該行不會被復制,而是"READY"會寫入文本,然后是換行符。

      您可能已經注意到海象運算符在這樣的構造中的附加值。此賦值表達式運算符的優先級是所有運算符中最低的。這意味著當賦值表達式是較大表達式的一部分時,您經常需要在其周圍添加括號,就像在 Java 中一樣。

      注意:?Python 沒有do {...} while (...)循環結構。

      Pythonfor循環類似于 Java 的 for-each 循環。這意味著,例如,如果您想遍歷前五個羅馬數字的列表,您可以使用類似的邏輯對其進行編碼:

      >>>

      >>> roman_numerals = "I II III IV V".split() >>> roman_numerals ['I', 'II', 'III', 'IV', 'V'] >>> for numeral in roman_numerals: ... print(numeral) ... I II III IV V

      您可能會注意到 usingstr.split()是一種創建單詞列表的便捷方式。

      注意:它不僅是list您可以通過這種方式迭代的實例,而且是任何可迭代的.

      有時,您可能需要一個運行計數器。在這種情況下,你會使用range():

      >>>

      >>> for i in range(5): ... print(i) ... 0 1 2 3 4

      在這個例子中,i每次迭代都引用請求范圍的下一個值。隨后打印該值。

      在極少數情況下,您想要迭代一個集合,同時想要在它旁邊有一個運行計數器,您可以使用enumerate():

      >>>

      >>> for i, numeral in enumerate("I II III IV V".split(), start=1): ... print(i, numeral) ... 1 I 2 II 3 III 4 IV 5 V

      上面的示例顯示了在一個循環中組合的前面兩個示例的功能。默認情況下,伴隨的計數器從零開始,但使用可選的關鍵字參數start,您可以指定另一個值。

      注:退房的Python枚舉():簡化環通設有專柜,如果你想了解更多關于Python循環和enumerate()。

      Python 也理解breakandcontinue語句。

      另一個類似于 Java 的控制流結構是以下if語句:

      >>>

      >>> for n in range(3): ... if n <= 0: ... adjective = "not enough" ... elif n == 1: ... adjective = "just enough" ... else: ... adjective = "more than enough" ... print(f"You have {adjective} items ({n:d})") ... You have not enough items (0) You have just enough items (1) You have more than enough items (2)

      如上所述,Pythonif ... else構造還支持elif關鍵字,這很有用,因為沒有簡單的switch ... case語句。

      注意:最近發布的 Python 3.10 版本包含一個名為結構模式匹配的新特性,它引入了match和case關鍵字,但它的行為與 Java 的switchstatement 有很大不同。

      這個新語言特性的靈感來自Scala的模式匹配語句,Scala 是另一種運行在 JVM 上的編程語言。

      盡管許多編碼結構表面上看起來很相似,但仍然存在許多差異。例如,Python 循環以及異常捕獲結構支持else:一部分。此外,Python為上下文管理器提供了一條with語句。

      Java 與 Python:什么是高級本機數據類型?

      在以下小節中,您將找到 Python 標準類型的簡要概述。重點是這些類型或其關聯運算符與 Java 的不同之處,或者它們與相應的 Java 集合類的比較。

      數字類型及其運算符

      Python 提供了多種數字類型供您選擇以適合您的特定應用領域。它內置了三種數字類型:

      如果比較這兩種語言,您會發現 Python 整數可以包含任意長值,僅受機器可用的(虛擬)內存量限制。您可以將它們視為固定精度本機整數(或原始整數類型,如 Java 所稱)和 JavaBigInteger數字的智能混合,結果如下:

      您擁有任意精度整數的所有便利,并且可以對它們使用所有眾所周知的符號運算符。

      當值足夠小以允許這樣做時,Python對提供的值應用快速固定精度整數算法。

      通過使用前綴0x、0o和0b,您可以分別將 Python 整數指定為十六進制、八進制和二進制常量。

      注意:這意味著八進制數的前綴不是只有一個或多個前導零 (?0),這與 Java 不同。

      比較著名的算術運算符+,?-,?*,?/, 以及%在 Java 與 Python 中,它們在兩種語言中具有相同的含義,除了類整數類型的除法運算符。應用于操作數的truediv運算符 (?/)在 Python 中int產生一個float值,這與 Java 不同。Python 具有用于除法的floordiv運算符 (?//),可向下舍入到最接近的整數,類似于/Java 中的除法運算符 (?):

      >>>

      >>> 11 / 4 # truediv 2.75 >>> 11.0 // 4 # floordiv, despite float operand(s) 2.0

      此外,Python**為求冪提供了雙星號運算符 (?) 作為雙參數pow()函數的替代方法。所述MATMUL運算符(@)被保留作為用于由外部的包提供的類型的額外的操作員,旨在作為一個方便的符號為矩陣乘法。

      Python 和 Java 都采用了 C 編程語言中的按位運算符。這意味著按位運算符(|、&、^和 一元~)在兩種編程語言中具有相同的含義。

      如果您想在負值上使用這些運算符,那么很高興知道在 Python 中,整數在概念上無限大的空間中表示為二進制補碼值來保存位。這意味著負值在概念上有無限多的前導1位,就像正數在概念上有無限多的前導0位:

      >>>

      >>> bin(~0) '-0b1' >>> bin(~0 & 0b1111) # ~0 is an "infinite" sequence of ones '0b1111'

      上面的代碼片段表明,無論您選擇哪個值,如果您將此值與常量 進行按位與運算~0,則結果值等于所選值。這意味著常量在~0概念上是一個無限的1位序列。

      的比特移位操作符(<<和>>)也是可用的。但是,沒有與 Java 的按位零填充右移運算符 (?>>>)等效的運算符,因為這在具有任意長整數的數字系統中毫無意義。沒有最重要的一點觸手可及。兩種語言之間的另一個區別是 Python 不允許以負移位計數移位位。

      Python 標準庫也提供其他數字類型。有decimal.Decimal十進制定點和浮點運算,可與 Java 的BigDecimal.?有一個fractions.Fraction用于有理數的類,可與Apache Commons Math Fractions相媲美。請注意,這些類型不屬于內置數字類型。

      基本序列類型

      序列類型是容器,您可以在其中使用整數索引訪問它們的元素。字符串和字節序列也是序列類型。稍后將介紹這些內容。Python 內置了三種基本的序列類型:

      如您所見,列表和元組初始值設定項之間的語法差異在于方括號 (?[]) 與圓括號 (?())。

      Python列表類似于 Java 的ArrayList,并且它是可變的。您通常將這種容器用于同類集合,就像在 Java 中一樣。然而,在 Python 中,可以存儲不相關類型的對象。

      一個元組,而另一方面,更類似于一個不可改變的一個版本Pair般類在Java中,除了它的條目,而不是兩個任意數量。空括號 (?()) 表示空元組。結構 like(3,)表示包含單個元素的元組。在這種情況下,單個元素是3。

      Java vs Python:Java 開發人員的基本 Python

      注意:您是否注意到tuple只有一個元素的a 的特殊語法?請參閱以下會話以發現差異:

      >>>

      >>> (3,) (3,) >>> type(_) >>> (3) 3 >>> type(_)

      如果您沒有添加尾隨逗號,則表達式將被解釋為括號內的對象。

      一個范圍得到的數字序列,你通常在循環使用。您已經在本教程的前面看到了一個示例。如果您想了解有關 Python 范圍的更多信息,可以查看本 range() 函數指南。

      要從序列中選擇一個元素,您可以在方括號之間指定從零開始的索引,如some_sequence[some_index]。負索引從末尾開始向后計數,因此-1表示最后一個元素。

      您還可以從序列中選擇一個切片。這是對零個、一個或多個元素的選擇,產生與原始序列類型相同的對象。你可以指定一個start,stop以及step價值,也被稱為步幅。切片語法的一個例子是some_sequence[::].

      所有這些值都是可選的,如果沒有另外指定,則采用實際的默認值。如果您想了解更多關于列表、元組、索引和切片的信息,閱讀Python 中的列表和元組將會很有幫助。

      對于正索引,Python 語法類似于在 Java 數組中選擇元素的方式。

      您可以使用加號運算符 (?+)連接大多數序列,并使用星號運算符 (?*)重復它們:

      >>>

      >>> ["testing"] + ["one", "two"] * 2 ['testing', 'one', 'two', 'one', 'two']

      您無法使用范圍完成串聯或序列重復,但可以對它們進行切片。例如,嘗試range(6, 36, 3)[7:2:-2]并考慮結果。

      字典

      Python 中的字典dict類似于 Java 中的LinkedHashMap.?dict 初始值設定key: value項常量的語法是花括號 (?{})之間以逗號分隔的條目序列。這方面的一個例子是{"pi": 3.14, "e": 2.71}。

      要從 dict 或任何其他映射中選擇元素,您可以在方括號 (?[])之間指定鍵,如math_symbols["pi"].?鍵和值都可以是任何對象,但鍵需要是hashable,這意味著它們通常是不可變的——或者至少應該表現得像不可變的對象。鍵不必都是相同類型的,盡管它們通常是。這同樣適用于價值觀。

      有關其他信息,您可以閱讀有關Python 中字典的更多信息,或查看有關映射類型的 Python 文檔。

      Sets

      Python 還提供了set。您可以{"pi", "e"}使用類似的語法或通過使用set()構造函數語法,使用可迭代對象作為參數來初始化集合。要創建空集,請使用表達式,set()因為文字{}已經提供給字典。

      集合在底層實現中使用散列。當您迭代一個集合時,請考慮到這些項目將以明顯隨機的順序出現,就像在 Java 中一樣。此外,順序甚至可能在不同的 Python 調用之間發生變化。

      一些運算符已被重載用于集合上的操作。有關詳細信息,您可以閱讀有關Python 中集合的更多信息。

      字符串

      就像在 Java 中一樣,Python 中的字符串是不可變的 Unicode 元素序列。字符串字面量在雙引號 (?")之間指定,也可以在單引號 (?')之間指定,這與 Java 不同。

      字符串的兩個示例是"foo"和'bar'。定義字符串時,不同的引號不一定具有任何不同的含義。但是,您應該注意,如果您將任何引號本身用作字符串的一部分,并且它們恰好也是字符串的分隔符,則您必須對它們進行轉義。

      與 Java 中一樣,\Python 中的反斜杠 (?) 是引入轉義序列的字符。Python解釋器識別Java也稱為轉義序列,如\b,\n,\t,和從C編程語言中的一些額外的。

      默認情況下,Python 假定您的 Python 源文件使用 UTF-8 編碼。這意味著您可以將 Unicode 文字直接放入字符串中,就像"é".?您還可以使用其代碼點的 16 位或 32 位十六進制表示。對于"é",您可以使用\u00E9或\U000000E9轉義序列來執行此操作。請注意小寫\u和大寫\U轉義序列之間的區別。最后,還可以提供其 Unicode 描述,例如\N{Latin Small Letter E with acute}.

      您甚至可以在 Python 標識符中使用 Unicode 字符,但問題是這是否是可取的做法。

      如果你在字符串前加上r,比如 in?r"raw\text",那么反斜杠就失去了它的特殊意義。當您要指定正則表達式時,這尤其方便。

      您還可以將字符串三重引用作為創建多行字符串的便捷方式,如下例所示:

      >>>

      >>> s = """This is a ... multiline ... string. ... """ ... >>> for line in s.splitlines(): ... print(repr(line)) ... 'This is a' ' multiline' ' string.' ' '

      您可以將這種類型的字符串與 Java文本塊 (JEP 378) 進行比較,盡管具有其他語法限制和另一種空格(制表符、空格和換行符)的保留。

      字節

      在 Java 中,如果您需要存儲二進制數據而不是text,您可能會使用ByteBuffer,它為您提供可變對象。在 Python 中,bytearray對象提供類似的功能。

      與 Java 不同,Python 還提供了一種bytes類型來存儲不可變的二進制數據。字節字面量看起來與字符串字面量非常相似,除了你在字面量前加上b.?字符串包含一個.encode()將它們轉換為字節序列的方法,一個bytes對象包含一個.decode()將其轉換為字符串的方法:

      >>>

      >>> bytes(4) # Zero-filled with a specified length b'\x00\x00\x00\x00' >>> bytes(range(4)) # From an iterable of integers b'\x00\x01\x02\x03' >>> b = "Attaché case".encode() # Many different codecs are available >>> b b'Attach\xc3\xa9 case' >>> b.decode() # Decode back into a string again 'Attaché case'

      如果未指定編解碼器,則默認 UTF-8 編解碼器用于編碼字符串和解碼字節。需要時,您可以從提供各種文本和字節轉換的大量編解碼器列表中進行選擇。

      Pythonbytes對象還有一個.hex()方法可以生成一個字符串,該字符串將以十六進制形式列出內容。對于反向操作,您可以使用.fromhex()?類方法bytes從十六進制字符串表示構造一個對象。

      布爾值

      False和True是boolPython中的兩個實例對象。在數字方面,True計算結果為1和False到0。這意味著True + True評估為2.

      在Python中的布爾邏輯運算符是從Java的不同&&,||以及!運營商。在Python,這些都是保留關鍵字and,or和not。

      您可以在下表中看到這一點:

      與 Java 類似,布爾運算符andand存在短路求值行為or,其中 Python 解釋器從左到右懶惰地求值操作數,直到它可以確定整個表達式的真實性。

      與 Java 的另一個相似之處是解釋器產生最后一個評估的子表達式作為結果。因此,您應該意識到andoror表達式的結果不一定會產生bool實例對象。

      所有的Python對象要么有一個falsy或truthy值。換句話說,當您將 Python 對象轉換為 時bool,結果是明確定義的:

      等于的數值0轉換為False,True否則轉換為。

      空容器、集合、字符串和字節對象轉換為False,True否則。

      該None對象皈依False為好。

      所有其他對象評估為True。

      注意:用戶定義的類可以提供一個.__bool__()dunder 方法來定義其類實例的真實性。

      如果要測試容器或字符串是否為非空,則只需在布爾上下文中提供該對象即可。這被認為是一種Pythonic方法。

      查看以下不同的方法來檢查非空字符串:

      >>>

      >>> s = "some string" >>> if s != "": # Comparing two strings ... print('s != ""') ... s != "" >>> if len(s) != 0: # Asking for the string length ... print("len(s) != 0") ... len(s) != 0 >>> if len(s): # Close, but no cigar ... print("len(s)") ... len(s) >>> if s: # Pythonic code! ... print("s") ... s

      在最后一個示例中,您只需在布爾上下文中提供字符串。如果字符串不為空,則它的計算結果為真。

      注意:以上并不意味著依賴于bool所有類型的隱式轉換是Pythonic?。下面的部分None更詳細地解決了這個問題。

      如果您想了解更多關于最典型的 Python 構造的信息,可以遵循編寫更多 Pythonic 代碼學習路徑。

      在 Python 中,您將使用條件運算符 (?)用 Java 編寫的條件表達式編碼為帶有關鍵字和的表達式:? :ifelse

      考慮 Python 中此類表達式的示例:

      >>>

      >>> for n in range(3): ... word = "item" if n == 1 else "items" ... print(f"Amount: {n:d} {word}") ... Amount: 0 items Amount: 1 item Amount: 2 items

      REPL"item"僅在n等于時輸出1。在所有其他情況下,REPL 輸出"items".

      沒有任何

      在 Python 中,None是一個單例對象,您可以使用它來識別類似空值的值。在 Java 中,您會null出于類似目的使用文字。

      NonePython 中最常使用的是作為函數或方法定義中的默認參數值。此外,不返回任何值的函數或方法實際上None隱式返回對象。

      一般來說,當您依賴于布爾上下文中的隱式轉換時,它被視為代碼異味,None因為您可能會為其他類型的對象編寫意外行為,而這些對象碰巧返回假值。

      因此,如果您想測試一個對象是否真的是該None對象,那么您應該明確地這樣做。因為只有一個None對象,您可以使用對象標識運算符is或相反的運算符來實現is not:

      >>>

      >>> some_value = "All" or None >>> if some_value is None: ... print(f"is None: {some_value}") >>> if some_value is not None: ... print(f"is not None: {some_value}") ... is not None: All

      請記住,not這里的單詞是is not運算符不可分割的一部分,它與邏輯not運算符顯然不同。在此示例中,字符串"All"在布爾上下文中具有一個真值。您可能還記得or運算符有這種短路行為,并且只要知道結果就立即返回最后一個表達式,"All"在這種情況下。

      更多容器數據類型

      Java 通過其集合框架提供其標準容器類型。

      Python 采用了不同的方法。它提供了您在本節前面探索的基本容器類型作為內置類型,然后 Python 的標準庫通過collections模塊提供了更多容器數據類型。您可以通過該collections模塊訪問許多有用的容器類型示例:

      namedtuple?提供元組,您還可以在其中通過字段名稱訪問元素。

      deque?提供雙端隊列,在集合的兩端快速追加和刪除。

      ChainMap?允許您將多個映射對象折疊到映射上的單個視圖中。

      Counter?提供用于計算可散列對象的映射。

      defaultdict?提供調用工廠函數來提供缺失值的映射。

      這些數據容器類型僅在純 Python 中實現。

      至此,您已為理解 Java 與 Python 的特性、語法和數據類型之間的異同奠定了良好的基礎。現在是時候退后一步,探索可用的 Python 庫和框架,并找出它們對特定用例的適用性。

      有哪些特定用途的資源?

      您可以在許多使用領域使用 Python。您將在下面找到其中一些領域,以及它們最有用和最流行的相關 Python 庫或框架:

      命令行腳本:?argparse提供創建命令行參數解析器的功能。

      網絡框架:

      在開發完整且可能復雜的網站時,Django提供了更多的收縮包裝方法。它包括定義模型的能力,提供自己的 ORM 解決方案,并提供完整的管理功能。您可以添加其他插件以進一步擴展管理。

      Flask 將自己標榜為一個專注于做好一件事的微框架,即服務于 Web 請求。您可以將此核心功能與您自己選擇的其他現有組件相結合,例如 ORM 和表單驗證。許多擴展,稱為 Flask 插件,可用于為您很好地集成這些組件。

      Requests使得發送 HTTP 請求非常方便。

      數據建模與分析:?pandas基于NumPy,是一款快速、強大、靈活、直接的開源數據分析與操作工具。有些人將熊貓稱為“類固醇的可編程電子表格”。

      機器學習:?TensorFlow,Keras和PyTorch在機器學習方面的幾個流行的框架。

      SQL 工具包和對象關系映射器 (ORM):?SQLAlchemy是一個非常流行的 Python SQL 工具包和 ORM 框架。

      工作負載分配:?Celery是一個分布式任務隊列系統。

      Python 還有一些值得注意的與質量保證相關的工具:

      pytest是標準unittest庫的絕佳替代品。

      行為是一種流行的行為驅動開發(BDD)工具。您可以將它與PyHamcrest結合使用以進行更具表現力的斷言檢查。

      Flake8是一個編碼風格指南檢查器。

      Pylint是一種工具,用于檢查 Python 代碼中的錯誤并識別代碼異味和編碼標準偏差。

      Black是不妥協、固執己見、難以配置的代碼重新格式化程序。盡管這聽起來很糟糕,但在現實生活中,它是任何大型軟件項目的絕佳工具。

      mypy是使用最廣泛的靜態類型檢查器。

      Bandit發現常見的安全問題。

      安全檢查您安裝的依賴項是否存在已知的安全漏洞。

      tox是一種命令行工具,可幫助運行在一個命令中為您的項目定義的自動化測試和 QA 工具檢查以及多個 Python 版本和依賴項配置。

      上面的列表只是眾多可用包和框架中的一小部分。您可以瀏覽和搜索 Python 包索引 (PyPI) 以找到您正在尋找的特殊包。

      Python 何時會比 Java 更有用,為什么?

      通常,您希望為一個用例選擇一種編程語言,為另一個用例選擇一種不同的編程語言。在比較 Java 與 Python 時,您應該考慮以下幾個方面:

      Java 和 Python 都成功地用于世界上最大的 Web 應用程序中。

      您還可以使用 Python 編寫 shell 工具。

      Python 優雅的語法、代碼可讀性、廣泛的庫和大量的外部包允許快速開發。您可能只需要不到一半的代碼行數即可實現與在 Java 中相同的功能。

      因為標準 Python 不需要編譯或鏈接步驟,所以當您更新代碼時,您會立即看到結果。這進一步加快了開發周期。

      在大多數情況下,對于一般應用程序,標準 Java 執行速度高于 Python。

      您可以相對輕松地使用 C 或 C++擴展Python。這在一定程度上緩解了執行速度的差異。

      對于某些用途,例如數據建模、分析、機器學習和人工智能,執行速度確實很重要。為此功能創建的流行的第三方包是用編譯為本機代碼的編程語言定義的。對于這些領域,Python 似乎是最合乎邏輯的選擇。

      結論

      在本教程中,您熟悉了 Python,并清楚地了解了這種編程語言的特性。您已經探索了 Java 和 Python 之間的異同。

      您現在已經有了一些快速入門 Python 的經驗。您也有一個很好的基礎來了解應用 Python 對哪些情況和哪些問題域有用,以及您接下來可以查看哪些有用資源的概述。

      在本教程中,您了解了:

      Python 編程語言的語法

      Python中相當多的標準數據類型

      Python與 Java 的不同之處

      Java和Python有哪些相似之處

      在哪里可以找到 Python文檔和特定主題的教程

      如何開始使用 Python

      如何使用 Python REPL查看即時結果

      一些最喜歡的框架和庫

      也許您確定將來會更多地使用 Python,或者您仍在決定是否更深入地研究該語言。無論哪種方式,通過上面總結的信息,您都可以很好地探索 Python 和本教程中介紹的一些框架。

      其他資源

      當您準備好了解有關 Python 及其軟件包的更多信息時,網絡上有大量可用資源:

      您可以找到涵蓋許多有關Real Python 的主題的書面教程、視頻課程、測驗和學習路徑。

      外部 Python 實用程序、庫和框架通常提供良好的文檔。

      PyVideo.org提供了大量免費提供的來自世界各地 Python 相關會議的演示文稿的索引集合。

      最后但同樣重要的是,官方Python 文檔對 Python 編程語言、其標準庫和生態系統的所有信息都保持了高標準的準確和完整的信息。

      現在您已經了解 Python 實際上是一種什么樣的編程語言,您希望對它充滿熱情,并考慮將它用于您的下一個項目,無論是小項目還是大項目。快樂的python!

      Java Python

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:做好的PPT沒保存不小心關掉了怎么辦(制作ppt突然被關掉了還沒保存怎么辦)
      下一篇:【愚公系列】2022年05月 .NET架構班 056-分布式中間件 .Net Core下Mongodb基本使用
      相關文章
      日韩亚洲人成网站| 亚洲a∨国产av综合av下载| vvvv99日韩精品亚洲| 亚洲国产高清国产拍精品| 中文文字幕文字幕亚洲色| 亚洲欧洲日产国码www| 亚洲视频中文字幕在线| 91亚洲自偷手机在线观看| 亚洲国产高清在线| 综合自拍亚洲综合图不卡区| 亚洲色成人网一二三区| 亚洲福利电影一区二区?| 亚洲第一成年网站大全亚洲| 亚洲剧情在线观看| 亚洲中字慕日产2021| 亚洲制服丝袜中文字幕| 亚洲日韩国产一区二区三区在线| 亚洲精品无AMM毛片| 亚洲Aⅴ在线无码播放毛片一线天| 亚洲av综合日韩| 亚洲国产精品自在拍在线播放| 亚洲精品无码成人片在线观看 | 亚洲国产高清美女在线观看| 亚洲伊人久久精品| 国产亚洲sss在线播放| 亚洲熟妇自偷自拍另欧美| 国产偷国产偷亚洲清高APP| 亚洲?V无码乱码国产精品| 亚洲一级片内射网站在线观看| 亚洲线精品一区二区三区| 亚洲av永久无码制服河南实里| 亚洲视频在线观看| 亚洲成a人片在线观看中文!!!| 97se亚洲国产综合自在线| 亚洲av无码一区二区三区人妖 | 亚洲无码视频在线| 亚洲男人的天堂www| 亚洲视频在线免费观看| 亚洲一级毛片在线播放| 亚洲夂夂婷婷色拍WW47| 亚洲&#228;v永久无码精品天堂久久|