最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python虛擬機(jī)之super超級(jí)魔法的使用和工作原理詳解

 更新時(shí)間:2023年10月13日 08:24:17   作者:一無是處的研究僧  
在本篇文章中,我們將深入探討Python中的super類的使用和內(nèi)部工作原理,super類作為Python虛擬機(jī)中強(qiáng)大的功能之一,super 可以說是 Python 對(duì)象系統(tǒng)基石,他可以幫助我們更靈活地使用繼承和方法調(diào)用,需要的朋友可以參考下

super類的使用

在 Python 中,我們經(jīng)常使用繼承來構(gòu)建類的層次結(jié)構(gòu)。當(dāng)子類繼承了父類的屬性和方法時(shí),有時(shí)我們需要在子類中調(diào)用父類的方法或?qū)傩?。這就是super類的用武之地。

super函數(shù)的一般用法是在子類中調(diào)用父類的方法,格式為super().method()。這樣可以方便地使用父類的實(shí)現(xiàn),并在子類中添加自己的特定行為。

下面是一個(gè)示例代碼,演示了super函數(shù)的使用:

class Parent:
    def __init__(self, name):
        self.name = name
    def say_hello(self):
        print(f"Hello, I'm {self.name}")
class Child(Parent):
    def __init__(self, name, age):
        super().__init__(name)
        self.age = age
    def say_hello(self):
        super().say_hello()
        print(f"I'm {self.name} and I'm {self.age} years old")
child = Child("Alice", 10)
child.say_hello()

輸出結(jié)果為:

Hello, I'm Alice
I'm Alice and I'm 10 years old

在上述示例中,Child類繼承自Parent類。在Child類的構(gòu)造函數(shù)中,我們使用super().__init__(name)來調(diào)用父類Parent的構(gòu)造函數(shù),以便在子類中初始化父類的屬性。在say_hello方法中,我們使用super().say_hello()調(diào)用父類Parentsay_hello方法,并在子類中添加了額外的輸出。

除了調(diào)用父類的方法,super函數(shù)還可以用于訪問父類的屬性。例如,super().attribute可以用來獲取父類的屬性值。

super類的工作原理

Super 設(shè)計(jì)的目的

要理解super類的工作原理,我們需要了解Python中的多重繼承和方法解析順序(Method Resolution Order,MRO)。多繼承是指一個(gè)類可以同時(shí)繼承多個(gè)父類。在Python中,每個(gè)類都有一個(gè)內(nèi)置屬性__mro__,它記錄了方法解析順序。MRO是根據(jù)C3線性化算法生成的,它決定了在多重繼承中調(diào)用方法的順序。當(dāng)對(duì)象進(jìn)行方法調(diào)用的時(shí)候,就會(huì)從類的 mro 當(dāng)中的第一個(gè)類開始尋找,直到最后一個(gè)類為止,當(dāng)?shù)谝淮伟l(fā)現(xiàn)對(duì)應(yīng)的類有相應(yīng)的方法時(shí)就進(jìn)行返回就調(diào)用這個(gè)類的這個(gè)方法。

Super 類的的簽名為 class super(type, object_or_type=None),這個(gè)類返回的是一個(gè) super 對(duì)象,也是一個(gè)代理對(duì)象,當(dāng)使用這個(gè)對(duì)象進(jìn)行方法調(diào)用的時(shí)候,這個(gè)調(diào)用會(huì)轉(zhuǎn)發(fā)給 type 父類或同級(jí)類。object_or_type 參數(shù)的作用是用于確定要搜索的方法解析順序(也就是通過object_or_type得到具體的 mro),對(duì)于方法的搜索從 type 后面的類開始。

例如,如果 的 object_or_type 的 mro 是 D -> B -> C -> A -> object 并且type的值是 B ,則進(jìn)行方法搜索的順序?yàn)?code>C -> A -> object ,因?yàn)樗阉魇菑?type 的下一個(gè)類開始的。

下面我們使用一個(gè)例子來實(shí)際體驗(yàn)一下:

class A:
	def __init__(self):
		super().__init__()
	def method(self):
		print("In method of A")
class B(A):
	def __init__(self):
		super().__init__()
	def method(self):
		print("In method of B")
class C(B):
	def __init__(self):
		super().__init__()
	def method(self):
		print("In method of C")
if __name__ == '__main__':
	print(C.__mro__)
	obj = C()
	s = super(C, obj)
	s.method()
	s = super(B, obj)
	s.method()

上面的程序輸出結(jié)果為:

(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
In method of B
In method of A

在上面的代碼當(dāng)中繼承順序?yàn)椋珻 繼承 B,B 繼承 A,C 的 mro 為,(C, B, A, object),super(C, obj) 表示從 C 的下一個(gè)類開始搜索,因此具體的搜索順序?yàn)?( B, A, object),因此此時(shí)調(diào)用 method 方法的時(shí)候,會(huì)調(diào)用 B 的 method 方法,super(B, obj) 表示從 B 的下一個(gè)類開始搜索,因此搜索順序?yàn)?(A, object),因此此時(shí)調(diào)用的是 A 的 method 方法。

Super 和棧幀的關(guān)系

在上一小節(jié)當(dāng)中我們?cè)谑褂?super 進(jìn)行測試的時(shí)候,都是給了 super 兩個(gè)參數(shù),但是需要注意的是我們?cè)谝粋€(gè)類的 __init__方法當(dāng)中并沒有給 super 任何參數(shù),那么他是如何找到 super 需要的兩個(gè)參數(shù)呢?

這其中的魔法就是在 Super 類對(duì)象的初始化會(huì)獲取當(dāng)前棧幀的第一個(gè)參數(shù)對(duì)象,這個(gè)就是對(duì)應(yīng)上面的 object_or_type 參數(shù),type 就是局部變量表當(dāng)中的一個(gè)參數(shù) __class__,我們可以通過查看類方法的局部變量去驗(yàn)證這一點(diǎn):

import inspect
class A(object):
	def __init__(self):
		super().__init__()
		print(inspect.currentframe().f_locals)
	def bar(self):
		pass
	def foo(self):
		pass
class Demo(A):
	def __init__(self):
		super().__init__()
		print(inspect.currentframe().f_locals)
	def bar(self):
		super().bar()
		print(inspect.currentframe().f_locals)
	def foo(self):
		print(inspect.currentframe().f_locals)
if __name__ == '__main__':
	demo = Demo()
	demo.bar()
	demo.foo()

上面的代碼輸出結(jié)果為:

{'self': <__main__.Demo object at 0x103059040>, '__class__': <class '__main__.A'>}
{'self': <__main__.Demo object at 0x103059040>, '__class__': <class '__main__.Demo'>}
{'self': <__main__.Demo object at 0x103059040>, '__class__': <class '__main__.Demo'>}
{'self': <__main__.Demo object at 0x103059040>}

從上面的例子我們可以看到當(dāng)我們進(jìn)行方法調(diào)用且方法當(dāng)中有 super 的使用時(shí),棧幀的局部變量表當(dāng)中會(huì)多一個(gè)字段 __class__,這個(gè)字段表示對(duì)應(yīng)的類,比如在 Demo 類當(dāng)中,這個(gè)字段就是 Demo,在類 A 當(dāng)中這個(gè)字段就是 A 。為什么要進(jìn)行這樣的處理呢,這是因?yàn)樾枰{(diào)用相應(yīng)位置類的父類方法,因此所有的使用 super 的位置的 type 都必須是所在類。而在前面我們已經(jīng)說明了object_or_type 表示的是棧幀當(dāng)中的第一個(gè)參數(shù),也就是對(duì)象 self,這一點(diǎn)從上面的局部變量表也可以看出來,通過這個(gè)對(duì)象我們可以知道對(duì)象本身的 mro 序列了。在 super 得到兩個(gè)參數(shù)之后,也就能夠?qū)崿F(xiàn)對(duì)應(yīng)的功能了。

CPython的實(shí)現(xiàn)

在本小節(jié)當(dāng)中我們來仔細(xì)看一下 CPython 內(nèi)部是如何實(shí)現(xiàn) super 類的,首先來看一下他的 __init__ 方法(刪除了error checking 代碼):

static int
super_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    superobject *su = (superobject *)self;
    PyTypeObject *type = NULL; // 表示從哪個(gè)類的后面開始查詢,含義和 上文當(dāng)中的 type 一樣
    PyObject *obj = NULL; // 表示傳遞過來的對(duì)象
    PyTypeObject *obj_type = NULL; // 表示對(duì)象 obj 的類型
    // 獲取 super 的兩個(gè)參數(shù) type 和 object_or_type
    if (!PyArg_ParseTuple(args, "|O!O:super", &PyType_Type, &type, &obj))
        return -1;
    if (type == NULL) {
        /* Call super(), without args -- fill in from __class__
           and first local variable on the stack. */
        PyFrameObject *f;
        PyCodeObject *co;
        Py_ssize_t i, n;
        f = _PyThreadState_GET()->frame; // 得到當(dāng)前棧幀
        // 棧幀的第一個(gè)參數(shù)表示對(duì)象
        obj = f->f_localsplus[0];
        if (obj == NULL && co->co_cell2arg) {
            /* The first argument might be a cell. */
            n = PyTuple_GET_SIZE(co->co_cellvars);
            for (i = 0; i < n; i++) {
                if (co->co_cell2arg[i] == 0) {
                    PyObject *cell = f->f_localsplus[co->co_nlocals + i];
                    assert(PyCell_Check(cell));
                    obj = PyCell_GET(cell);
                    break;
                }
            }
        }
        if (co->co_freevars == NULL)
            n = 0;
        else {
            assert(PyTuple_Check(co->co_freevars));
            n = PyTuple_GET_SIZE(co->co_freevars);
        }
        // 下面的代碼表示獲取 type 對(duì)象,也就是從局部變量表當(dāng)中獲取到 __class__ 
        for (i = 0; i < n; i++) {
            PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i);
            assert(PyUnicode_Check(name));
            if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {
                Py_ssize_t index = co->co_nlocals +
                    PyTuple_GET_SIZE(co->co_cellvars) + i;
                PyObject *cell = f->f_localsplus[index];
                type = (PyTypeObject *) PyCell_GET(cell);
                break;
            }
        }
    }
    if (obj == Py_None)
        obj = NULL;
    if (obj != NULL) {
        // 這個(gè)函數(shù)是用于獲取 obj 的 type
        obj_type = supercheck(type, obj);
        if (obj_type == NULL)
            return -1;
        Py_INCREF(obj);
    }
    return 0;
}

在上面的代碼執(zhí)行完成之后就得到了一個(gè) super 對(duì)象,之后在進(jìn)行函數(shù)調(diào)用的時(shí)候就會(huì)將對(duì)應(yīng)類的方法和對(duì)象 obj 綁定成一個(gè)方法對(duì)象返回,然后在進(jìn)行方法調(diào)用的時(shí)候就能夠成功調(diào)用了。

class Demo:
	def __init__(self):
		print(super().__init__)
if __name__ == '__main__':
	Demo()

輸出結(jié)果:

<method-wrapper '__init__' of Demo object at 0x100584070>

總結(jié)

super 是 Python 面向?qū)ο缶幊坍?dāng)中非常重要的一部分內(nèi)容,在本篇文章當(dāng)中詳細(xì)介紹了 super 內(nèi)部的工作原理和 CPython 內(nèi)部部分源代碼分析了 super 的具體實(shí)現(xiàn)。在 Python 當(dāng)中 super 的使用方式分為兩種一種是可以直接使用參數(shù),另外一種是在類的方法當(dāng)中不使用參數(shù),后者的實(shí)現(xiàn)稍微復(fù)雜一點(diǎn),他會(huì)從當(dāng)前棧幀和局部變量表當(dāng)中分別取出類對(duì)象和類,作為 super 的參數(shù),從而實(shí)現(xiàn) super 的功能。

以上就是Python虛擬機(jī)之super超級(jí)魔法的使用和原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Python super超級(jí)魔法原理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python魔術(shù)方法詳解

    Python魔術(shù)方法詳解

    這篇文章主要介紹了Python魔術(shù)方法詳解,本文講解了構(gòu)造和初始化、用于比較的魔術(shù)方法、數(shù)值處理的魔術(shù)方法、普通算數(shù)操作符等內(nèi)容,需要的朋友可以參考下
    2015-02-02
  • Python 獲取當(dāng)前所在目錄的方法詳解

    Python 獲取當(dāng)前所在目錄的方法詳解

    本文給大家講解的是使用python獲取當(dāng)前所在目錄的方法以及相關(guān)示例,非常的清晰簡單,有需要的小伙伴可以參考下
    2017-08-08
  • Python實(shí)現(xiàn)查找字符串?dāng)?shù)組最長公共前綴示例

    Python實(shí)現(xiàn)查找字符串?dāng)?shù)組最長公共前綴示例

    這篇文章主要介紹了Python實(shí)現(xiàn)查找字符串?dāng)?shù)組最長公共前綴,涉及Python針對(duì)字符串的遍歷、判斷、計(jì)算等相關(guān)操作技巧,需要的朋友可以參考下
    2019-03-03
  • Django admin管理工具TabularInline類用法詳解

    Django admin管理工具TabularInline類用法詳解

    這篇文章主要介紹了Django admin管理工具TabularInline類用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • python實(shí)現(xiàn)通過pil模塊對(duì)圖片格式進(jìn)行轉(zhuǎn)換的方法

    python實(shí)現(xiàn)通過pil模塊對(duì)圖片格式進(jìn)行轉(zhuǎn)換的方法

    這篇文章主要介紹了python實(shí)現(xiàn)通過pil模塊對(duì)圖片格式進(jìn)行轉(zhuǎn)換的方法,涉及Python中pil模塊的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • Python?pycharm讀取文件相對(duì)路徑與絕對(duì)路徑的方法

    Python?pycharm讀取文件相對(duì)路徑與絕對(duì)路徑的方法

    這篇文章主要給大家介紹了關(guān)于Python?pycharm讀取文件相對(duì)路徑與絕對(duì)路徑的方法,絕對(duì)路徑就是文件的真正存在的路徑,是指從硬盤的根目錄(盤符)開始,進(jìn)行一級(jí)級(jí)目錄指向文件,相對(duì)路徑就是以當(dāng)前文件為基準(zhǔn)進(jìn)行一級(jí)級(jí)目錄指向被引用的資源文件,需要的朋友可以參考下
    2023-12-12
  • 詳解Django3中直接添加Websockets方式

    詳解Django3中直接添加Websockets方式

    這篇文章主要介紹了Django3中直接添加Websockets方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • Keras: model實(shí)現(xiàn)固定部分layer,訓(xùn)練部分layer操作

    Keras: model實(shí)現(xiàn)固定部分layer,訓(xùn)練部分layer操作

    這篇文章主要介紹了Keras: model實(shí)現(xiàn)固定部分layer,訓(xùn)練部分layer操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • 使用python實(shí)現(xiàn)讀取文件夾中所有excel

    使用python實(shí)現(xiàn)讀取文件夾中所有excel

    相信很多坐在辦公室上班的朋友每天都需要處理大量的數(shù)據(jù),本文我們就來看看如何使用Openpyxl讀取文件夾下所有Excel文檔中的數(shù)據(jù),文中示例代碼講解詳細(xì),感興趣的小伙伴可以了解下
    2025-12-12
  • Python基于DFA算法實(shí)現(xiàn)內(nèi)容敏感詞過濾

    Python基于DFA算法實(shí)現(xiàn)內(nèi)容敏感詞過濾

    DFA?算法是通過提前構(gòu)造出一個(gè)?樹狀查找結(jié)構(gòu),之后根據(jù)輸入在該樹狀結(jié)構(gòu)中就可以進(jìn)行非常高效的查找。本文將利用改算法實(shí)現(xiàn)敏感詞過濾,需要的可以參考一下
    2022-04-04

最新評(píng)論

安阳市| 南华县| 栖霞市| 宁都县| 安化县| 宁明县| 桃园县| 余江县| 肇庆市| 嘉峪关市| 门源| 龙口市| 三明市| 措勤县| 淮南市| 东丰县| 揭阳市| 江口县| 汽车| 武乡县| 洪洞县| 珲春市| 炎陵县| 洱源县| 明水县| 新巴尔虎右旗| 桦川县| 肇东市| 永福县| 新乡县| 思茅市| 米易县| 闽侯县| 文水县| 太和县| 英吉沙县| 黄龙县| 许昌县| 石泉县| 乌拉特后旗| 肥西县|