學編程這麼久,還傻傻分不清什麼是方法(method),什麼是函數(function)?

来源:https://www.cnblogs.com/pythonista/archive/2020/04/09/12670052.html
-Advertisement-
Play Games

在編程語言中有兩個很基礎的概念,即方法(method)和函數(function)。如果達到了編程初級/入門級水平,那麼你肯定在心中已有了初步的答案。 也許在你心中已有答案了 除去入參、返回值、匿名函數之類的正確的形式內容之外,你也許會說“函數就是定義在類外面的,而方法就是定義在類裡面的,跟類綁定的” ...


在編程語言中有兩個很基礎的概念,即方法(method)和函數(function)。如果達到了編程初級/入門級水平,那麼你肯定在心中已有了初步的答案。

也許在你心中已有答案了

除去入參、返回值、匿名函數之類的正確的形式內容之外,你也許會說“函數就是定義在類外面的,而方法就是定義在類裡面的,跟類綁定的”。

這種說法有沒有問題呢?當然有!不然我就不會專門寫這篇文章了,本文主要會來釐清這個問題。

在標準庫inspect 中,它提供了兩個自省的函數,即 ismethod() 和 isfunction(),可以用來判斷什麼是方法,什麼是函數。

因此,本文想要先來研究一下這兩個函數,看看 Python 在處理方法/函數的概念時,是怎麼做的?

關於它們的用法,先看一個最簡單的例子:

運行的結果分別是“True”和“False”,表明我們所定義的 test() 是一個函數,而不是一個方法。

這兩個函數也可以用來檢測自身,不難驗證出它們都是一種函數:

那麼,接下來的問題是:inspect 庫的兩個函數是什麼工作原理呢?

先來看看 inspect 中的實現代碼:

在源碼中,我們看到了 isinstance() 函數,它主要用於判斷一個對象(object)是否是某個類(class)的實例(instance)。

我們還看到了 types.FunctionTypetypes.MethodType ,它們指的就是目標類。繼續點進去看源碼:

# 摘自 types.py
def _f(): pass
FunctionType = type(_f)

class _C:
    def _m(self): pass
MethodType = type(_C()._m)

這裡只是定義了兩個空的 _f() 和 _m(),然後就使用了內置的 type() 函數。所以,我們完全可以把它們摘出來,看看廬山真面目:

梳理它們的關係,可以得到:

經過簡化處理後,我們發現最關鍵的是兩個問題:type() 函數如何判斷出一個對象是 function 或 method 類?instance() 函數如何判斷出一個對象是某個類的實例?

這兩個內置函數都是用 C 語言實現的,這裡我就不打算繼續深究了……

但是,讓我們再回頭看看 inspect 中的註釋,就會註意到一些端倪:

  • isfunction() 判斷出的是用戶定義的函數(user-defined function), 它擁有__doc__、__name__ 等等屬性
  • ismethod() 判斷出的是實例方法(instance method), 它擁有函數的一些屬性,最特別的是還有一個 __self__ 屬性

還是註釋更管用啊,由此我們能得到如下的推論:

1、非用戶定義的函數,即內置函數,在 isfunction() 眼裡並不是“函數”(FunctionType)!

下麵驗證一下 len()、dir() 和 range():

事實上,它們有專屬的類別(BuiltinFunctionType、BuiltinMethodType):

特別需要註意的是,內置函數都是builtin_function_or_method 類型,但是 range()、type()、list() 等看起來像是函數的,其實不然:

(PS:關於這點,我這篇文章 曾提到過,就不再展開了。)

2、一個類的靜態方法,在 ismethod() 眼裡並不是方法(MethodType)!

創建了類的實例後,再看看:

可以看出,除了 classmethod 之外,只有類實例的實例方法,才會被 ismethod() 判定為真!而靜態方法,不管綁定在類還是實例上,都不算是“方法”!

有沒有覺得很不可思議(或者有點理不清了)?

好了,回到本文開頭的問題,我們最後來小結一下吧。

若以 inspect 庫的兩個函數為判斷依據,則 Python 中的“方法與函數”具有一定的狹義性。在判斷什麼是函數時,它們並不把內置函數計算在內。同時,在判斷什麼是方法時,並非定義在類內部的都算,而是只有類方法及綁定了實例的實例方法才算是“方法”。

也許你會說,inspect 的兩個判斷函數並不足信,內置函數也應該算是“函數”,類裡面的所有方法都應該算是“方法”。

我承認這種說法在廣義上是可接受的,畢竟我們一直叫的就是“XX函數”、“XX方法”嘛。

但是,理論和廣義概念只是方便人們的溝通理解,而代碼實現才是本質的區別。也就是說,Python 在實際區別“方法與函數”時,並不是文中開頭的簡單說法,還有更多的細節值得關註。

看完本文,你有什麼想法呢?歡迎一起交流。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、join方法 1.該方法為成員方法 2.線程合併 package com.bjpowernode.java_learning; ​ public class D107_1_JoinMethod { public static void main(String[] args) throws Int ...
  • 1. 回顧Boosting提升演算法 AdaBoost是典型的Boosting演算法,屬於Boosting家族的一員。在說AdaBoost之前,先說說Boosting提升演算法。Boosting演算法是將“弱學習演算法“提升為“強學習演算法”的過程,主要思想是“三個臭皮匠頂個諸葛亮”。一般來說,找到弱學習演算法要 ...
  • java克隆 為什麼需要克隆 我們在很多時候需要使用一個對象去記錄另外一個對象的當前狀態,對象中可能會有很多屬性,如果我們一個一個去設置,不僅不方便,而且效率很低,我們看一個初學者可能遇到的問題 也許有的人認為Person p2=p1這樣的方式就可以克隆一個對象,這種想法是錯誤的,這種使用等號賦值的 ...
  • 今天記錄一下驗證碼的實現,希望能夠幫助到大家! 首先我們看一下實現的效果: 此驗證碼的實現沒有用到太多的插件,話不多說直接上代碼,大家拿過去就可以用。 中間用到了org.apache.commons.lang3.RandomUtils工具類,需要pom配置: <!-- https://mvnrepo ...
  • 筆者:風起怨江南 出處:https://www.cnblogs.com/mengjinxiang 筆者原創,文章歡迎轉載,如果喜歡請點贊+關註,謝謝! 問題:window系統下,如果升級了最新的Python版本(比如當前Python3.7.7版本),需要卸載以前的Python版本麽?安裝後如何切換版 ...
  • 讀取整個文件 整個文件讀取到記憶體是最基本的文件操作之一。這需要使用 包中的 函數。 以上使用的是運行時指定參數 來指定讀取的文件,也可以使用文件的絕對路徑。 分塊讀取文件 當文件非常大時,尤其在記憶體不足的情況下,把整個文件都讀入記憶體是沒有意義的。 更好的方法是分塊讀取文件。這可以使用 包來完成。 利 ...
  • 作者:龍躍十二鏈接:https://www.imooc.com/article/300814 ,微信公眾號:龍躍十二 數組的基本概念 我們把一組數據的集合稱為數組(Array),它所包含的每一個數據叫做數組元素(Element),所包含的數據的個數稱為數組長度(Length),數組中的每個元素都有一 ...
  • 1.派生類作為實參賦給父類形參 一般的父類只繼承子類中共同的部分,子類的新方法會被自動忽略而父類也就無法調用子類的新方法了。 問題:用父類的形參來訪問子類的新方法。 強制類型轉換(這個可能會有風險,但是編譯器不報錯) class Animal{ public: void Live(){ cout<< ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...