學編程這麼久,還傻傻分不清什麼是方法(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
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...