python3.x - 关于Python的super用法一处不解

查看:154
本文介绍了python3.x - 关于Python的super用法一处不解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

描述问题

以前以为自己知道super怎么用,但是看到下面的代码,却是没有搞懂其作用原理

下面的代码,神奇地做到了"属性设置不能为int" (实现在父类里面)

查阅了super的用法,摘抄如下

super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type) -> unbound super object
super(type, type2) -> bound super object; requires issubclass(type2, type)  #这种用法没见过
Typical use to call a cooperative superclass method:

摘录官方文档如下 (就是第二个参数为type时,不太明白那一段英文的意思)

super(type[, object-or-type]) 
Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped.

The __mro__ attribute of the type lists the method resolution search order used by both getattr() and super(). The attribute is dynamic and can change whenever the inheritance hierarchy is updated.

If the second argument is omitted, the super object returned is unbound. If the second argument is an object, isinstance(obj, type) must be true. If the second argument is a type, issubclass(type2, type) must be true (this is useful for classmethods).

上下文环境

  1. Python3

重现

相关代码

class Person:
    def __init__(self, name):
        self.name = name
    # Getter function
    @property
    def name(self):
        return self._name
    # Setter function
    @name.setter
    def name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._name = value
    # Deleter function
    @name.deleter
    def name(self):
        raise AttributeError("Can't delete attribute")
        
        
        
        
        
class SubPerson(Person):
    @property
    def name(self):
        print('Getting name')
        return super().name
    @name.setter
    def name(self, value):
        print('Setting name to', value)
        super(SubPerson, SubPerson).name.__set__(self, value)  ##??? 这种用法第一次见, 作用原理/作用流程是什么?
        #返回一个父类的实例,然后调用其方法
        #关键是: super(SubPerson, SubPerson) 如何使用的?
    @name.deleter
    def name(self):
        print('Deleting name')
        super(SubPerson, SubPerson).name.__delete__(self)  

报错信息

解决方案

這個問題簡而言之, super(SubPerson, SubPerson).name 會調用 Person.name 的 setter, 而:

if not isinstance(value, str):
    raise TypeError('Expected a string')

這個檢查將會引發 TypeError 當設定值並非 string 的時候。


如果這個地方沒問題, 我們再回頭來看 super 做了什麼, 要理解 super 並避免一些誤解, 簡單來說理解三件事:

  1. super 不一定指涉到父類, 他指涉的是 mro 中的下一個類

  2. 在 mro 中, 基礎類別一定出現在衍生類別之後, 若有多個基礎類別, 其相對順序保持不變

  3. super 對象並非其指涉的類別, 他的作用只是代理委託

super 不一定指涉到父類, 他指涉的是 mro 中的下一個類

那假設大家對 mro 都有一定程度的理解(若不太理解, 我們可以再討論)

super 在做的事情可用下面的代碼理解:

def super(cls, inst):
    mro = inst.__class__.mro()
    return mro[mro.index(cls) + 1]

這可以說是理解 super 的關鍵之處 (很多人覺得自己懂 super, 其實看完這段代碼會發現還不太懂XD)

  1. super 會去找出第二個參數(可以是類可以是對象) 的 mro

  2. 返回 mro 中在第一個參數 cls 的下一個類

舉例來說:

In [14]: import person

In [15]: from person import SubPerson

In [16]: sp = SubPerson('Guido')
Setting name to Guido

In [17]: sp.__class__.mro()
Out[17]: [person.SubPerson, person.Person, object]

  • super(SubPerson, sp) 指的是 Person (mro 中 sp的類:SubPerson 的下一個)

  • super(SubPerson, SubPerson) 指的是 Person (mro 中 SubPerson 的類:SubPerson 的下一個)

  • super(SubPerson, Person) 指的是 object (mro 中 Person 的類:Person 的下一個)

這邊可能還有兩個問題是:

  • super 可以在類別外部使用?

    • 是的, super 是一個內建函數, 不限制在 class 內部使用

  • super 可以省略參數嗎?

    • 在類的外部使用時, 不允許省略參數, 不然不知道是找誰的 mro, 也不知道找誰的下一個

    • 在類的內部使用時, 允許省略參數, 這個狀況下, 找的是自己的 mro, 找自己的下一個

那為什麼會說 super 不一定指涉到父類, 他指涉的是 mro 中的下一個類呢? 很簡單, 多重繼承的情況之下, mro 的下一個類很可能不是 父類(Parent)兄弟類(Sibling)

但多數的情況下, 我們會希望 super 幫我們找到單繼承下的直接父類別, 所以我們會傾向在類別內部, 完全省略參數來調用 super()

另外兩點

  • 第二點是個重要的觀念, 但假設對 mro 有一定的認知的話, 這是個基本觀念

  • 第三點的話是一個迷思, 我們並不能透過 super 拿到指涉的那個類, 只能夠透過 super 對象的代理去委託指涉類的 method 做事情

不知道以上有沒有解決你的疑惑呢?


我回答過的問題: Python-QA

这篇关于python3.x - 关于Python的super用法一处不解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆