目錄
一、super函數的常見應用場景
二、super函數使用注意事項
三、如何用好super函數?
1、super函數:
1-1、Python:
1-2、VBA:
2、推薦閱讀:
個人主頁:?https://myelsa1024.blog.csdn.net/
一、super函數的常見應用場景
????????在Python中,super()函數在面向對象編程的繼承關系中有著廣泛的應用,常見的應用場景有:
1、構造函數調用:在子類的構造函數中,super()函數可以用于調用父類的構造函數,確保子類對象具有父類的屬性和行為,這是通過super().__init__(...)實現的,其中`...`是傳遞給父類構造函數的參數。
2、方法調用:super()函數也可以在子類中用于調用父類的方法,這允許子類在需要時重用或擴展父類的方法。例如,super().method_name(...)會調用父類中定義的method_name方法。
3、混入類(Mixin):混入類是一種特殊類型的類,旨在通過多重繼承為其他類提供額外的功能,在混入類中使用super()函數可以確保方法的調用順序是按照繼承鏈的順序來執行的,從而保持代碼的一致性和可維護性。
4、多重繼承:在多重繼承的場景中,super()函數特別有用,多重繼承允許一個類繼承自多個父類,但這也可能導致方法調用沖突或混淆,使用super()函數可以確保方法按照預定的順序(即方法解析順序,MRO)被調用,從而避免這些問題。
5、修改繼承結構:通過動態地改變繼承關系,可以使用super()函數來創建更靈活的類結構。例如,可以使用type()函數在運行時創建新類,并將它們添加到現有的繼承結構中。
6、框架和庫開發:在開發框架或庫時,super()函數經常用于實現可擴展的API,框架可以定義一些基類,這些基類提供了一些默認的行為,而開發者可以通過繼承這些基類并覆蓋其中的方法來擴展這些行為。通過使用super()函數,子類可以確保在覆蓋方法時不會丟失父類的功能。
7、設計模式實現:super()函數也可以用于實現一些設計模式,如模板方法模式、組合模式等,在這些模式中,super()函數可以幫助子類在擴展功能時保持與父類的一致性。
????????注意,雖然super()函數提供了強大的功能,但在使用它時也需要謹慎;過度使用super()函數可能會導致代碼難以理解和維護,因此,在決定是否使用super()函數時,應該仔細考慮其是否真正符合你的需求,并權衡其帶來的好處和潛在的問題。
二、super函數使用注意事項
????????在Python中使用super()函數時,需要注意以下幾個事項:
1、確保使用在正確的方法中:super()函數通常用于調用父類(或兄弟類,在多重繼承的情況下)的方法,尤其是在`__init__`、`__enter__`、`__exit__`以及其他一些你可能需要重寫的特殊方法或常規方法中,不過,不是所有的方法都需要或應該使用super()函數。
2、在子類中始終使用super()函數:如果你決定在一個子類的某個方法中使用super()函數來調用父類的方法,那么在該子類的所有子類中,你也應該使用super()函數來調用該方法,以保持繼承的一致性。
3、不要調用super()函數超過一次:在同一個方法內,不要多次調用super()函數來執行同一個父類方法,除非你有明確的理由要這樣做,這可能會導致父類方法被多次執行,從而產生意外的副作用。
4、理解方法解析順序(MRO):在多重繼承的情況下,Python使用C3線性化算法來確定方法解析順序(MRO),了解MRO的工作原理有助于你理解super()函數是如何工作的,以及為什么它會按照特定的順序調用父類方法。
5、注意Python 2和Python 3的區別:Python 2和Python 3在super()函數的使用上有所不同:在Python 2中,super()通常需要傳入兩個參數:類本身和實例;而在Python 3中,super()可以不帶參數調用,Python會自動推斷出這兩個參數。
6、避免直接引用父類:當你使用super()函數時,最好不要直接引用父類名來調用方法,這樣做會破壞繼承的靈活性,因為如果你更改了父類,或者類被繼承自不同的父類,那么你的代碼就需要進行更改,使用super()函數可以確保你的代碼更加健壯和可維護。
7、不要在靜態方法/類方法/屬性上使用super()函數:super()函數用于在實例方法之間建立合作關系,以便在調用時正確地訪問繼承的層次結構,靜態方法、類方法和屬性與實例無關,因此它們不應該使用super()函數。
8、不要過度使用super()函數:雖然super()函數在某些情況下非常有用,但過度使用它可能會導致代碼難以理解和維護,在決定使用super()函數之前,請確保它確實能夠簡化你的代碼并提高可維護性。
三、如何用好super函數?
????????在Python中,要正確地使用super()函數,需遵循以下建議:
1、理解繼承和多態:在使用super()函數之前,確保你理解面向對象編程中的繼承和多態概念,super()函數主要用于在子類中調用父類的方法,以支持繼承和多態。
2、遵循Python的繼承約定:在Python中,如果類要設計為被繼承,那么它的構造函數(`__init__`方法)應該總是調用其基類的構造函數,這通常通過使用super().__init__()來完成,這樣做可以確保基類中的任何初始化邏輯都能被執行,且子類可以在其基礎上添加或修改狀態。
3、避免直接引用父類:在子類中,盡量避免直接引用父類的類名來調用其方法,使用super()代替直接引用,可以增加代碼的靈活性和可維護性,當類層次結構發生變化時(例如,更改了父類),使用super()函數的代碼通常不需要修改。
4、理解方法解析順序(MRO):在多重繼承的情況下,了解Python的MRO(方法解析順序)是非常重要的,這有助于你理解super()函數是如何在多個父類之間查找和調用方法的,Python使用C3線性化算法來確定MRO。
5、注意super()函數的調用上下文:在子類中調用super()時,它會自動綁定到當前實例和當前類,這意味著你不需要顯式地傳遞這些參數,但是,請注意super()函數的調用上下文必須在類的定義內部,如果你在類外部(例如在實例方法或普通函數中)調用super()函數,它將無法正常工作。
6、謹慎使用super()在靜態方法或類方法中:由于靜態方法和類方法與實例無關,因此它們通常不需要使用`super()`來調用父類的方法,如果你需要在靜態方法或類方法中訪問父類的行為,請考慮將其重構為實例方法或使用其他設計模式。
7、不要過度使用super()函數:雖然super()函數在某些情況下非常有用,但過度使用它可能會導致代碼變得復雜和難以理解,在決定是否使用super()函數時,請權衡其帶來的好處和潛在的問題,如果可能的話,盡量保持代碼簡單和直觀。
8、測試你的代碼:在使用super()函數時,確保對你的代碼進行充分的測試,這有助于確保你的代碼在所有預期的情況下都能正常工作,并幫助你發現任何潛在的問題或錯誤。
9、閱讀文檔和示例:Python的官方文檔和社區資源提供了大量關于super()函數的文檔和示例,閱讀這些資源可以幫助你更深入地了解super()函數的工作原理和最佳實踐。
10、實踐:最后但同樣重要的是,通過實踐來熟悉super()函數的使用,嘗試在小型項目中使用它,并逐步擴展到更大的項目中;通過實踐,你將能夠更好地理解super()函數的用途和限制,并找到最適合你的編程風格和工作流程的方法。
1、super函數:
1-1、Python:
# 1.函數:super
# 2.功能:用于調用父類(超類)的一個方法,該方法多用來解決多重繼承的問題
# 3.語法:super([type[, object_or_type=None]])
# 4.參數:
# 4-1、type:類
# 4-2、object_or_type:確定用于查找的順序MRO(method resolution order),此時,搜索會從type所指定的類之后的類開始,通常情況下,設置為self
# 5.返回值:返回一個代理對象,它會將方法調用委托給type的父類或兄弟類
# 6.說明:
# 6-1、單繼承:可以直接使用類名調用父類方法
# 6-2、多繼承:涉及查找順序MRO(method resolution order)、重復調用(鉆石繼承)等多種問題時,需要使用super()函數來調用
# 7.示例:
# 用dir()函數獲取該函數內置的屬性和方法
print(dir(super))
# ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__',
# '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__',
# '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__self_class__', '__setattr__', '__sizeof__', '__str__',
# '__subclasshook__', '__thisclass__']# 用help()函數獲取該函數的文檔信息
help(super)# 應用一:構造函數調用
# 示例1:單繼承示例
class Parent:def __init__(self, parent_attr):self.parent_attr = parent_attrprint(f"Parent.__init__ called with {parent_attr}")
class Child(Parent):def __init__(self, parent_attr, child_attr):super().__init__(parent_attr) # 調用父類的構造函數self.child_attr = child_attrprint(f"Child.__init__ called with {child_attr}")
# 使用示例
c = Child("parent", "child")
# Parent.__init__ called with parent
# Child.__init__ called with child# 示例2:多繼承示例
class Parent1:def __init__(self, attr1):self.attr1 = attr1print(f"Parent1.__init__ called with {attr1}")
class Parent2:def __init__(self, attr2):self.attr2 = attr2print(f"Parent2.__init__ called with {attr2}")
class Child(Parent1, Parent2):def __init__(self, attr1, attr2, child_attr):super().__init__(attr1) # 通常會調用方法解析順序(MRO)中的第一個父類# 如果需要顯式地調用第二個父類的構造函數,你可以這樣做:# Parent2.__init__(self, attr2)# 但通常不推薦這樣做,因為它打破了使用super()的初衷# 另一種方法是通過super()多次調用,但這取決于具體的MRO和Python版本# 例如,在Python 3中,你可以這樣做(但這不是標準做法):# super(Parent1, self).__init__(attr2)# 在這個例子中,我們假設Parent2的初始化不依賴于Parent1,所以我們可以直接調用它Parent2.__init__(self, attr2)self.child_attr = child_attrprint(f"Child.__init__ called with {child_attr}")
# 使用示例
c = Child("parent1", "parent2", "child")
# Parent1.__init__ called with parent1
# Parent2.__init__ called with parent2
# Child.__init__ called with child# 應用二:方法調用
# 示例1:單繼承示例
class Parent:def greet(self):print("Hello from Parent!")
class Child(Parent):def greet(self):super().greet() # 調用父類的greet方法print("Hello from Child!")
# 使用示例
c = Child()
c.greet()
# Hello from Parent!
# Hello from Child!# 示例2:多繼承示例
class Grandparent:def greet(self):print("Hello from Grandparent!")
class Parent1(Grandparent):def greet(self):super().greet() # 調用Grandparent的greet方法print("Hello from Parent1!")
class Parent2:def greet(self):print("Hello from Parent2!")
class Child(Parent1, Parent2):def greet(self):super().greet() # 調用Parent1的greet方法,它會繼續調用Grandparent的greet方法print("Hello from Child!")
# 使用示例
c = Child()
c.greet()
# Hello from Grandparent!
# Hello from Parent1!
# Hello from Child!# 應用三:混入類(Mixin)
class LoggingMixin:def log(self, message):print(f"Logging: {message}")# 不再需要調用super().do_something(),因為LoggingMixin沒有基類def do_something_after_logging(self):self.log("Something was done.")
class BaseClass:def do_something(self):print("BaseClass: Doing something.")
class MyClass(BaseClass, LoggingMixin):def __init__(self):super().__init__() # 注意:這里實際上并沒有在BaseClass或LoggingMixin中定義__init__,但為了習慣還是調用了def do_something(self):super().do_something() # 調用BaseClass的do_something方法self.do_something_after_logging() # 調用LoggingMixin的do_something_after_logging方法來記錄日志
# 使用示例
obj = MyClass()
obj.do_something() # 輸出:BaseClass: Doing something. 和 Logging: Something was done.
# BaseClass: Doing something.
# Logging: Something was done.# 應用四:多重繼承
class ParentA:def __init__(self):print("Initializing ParentA")super().__init__() # 通常情況下,ParentA沒有父類,這行是可選的def feature(self):print("Feature from ParentA")
class ParentB:def __init__(self):print("Initializing ParentB")super().__init__() # 通常情況下,ParentB沒有父類,這行是可選的def feature(self):print("Feature from ParentB")
class Child(ParentA, ParentB):def __init__(self):print("Initializing Child")super().__init__() # 調用MRO中的下一個類的__init__方法def feature(self):print("Starting Child feature")super().feature() # 調用MRO中的下一個類的feature方法print("Finishing Child feature")
# 使用示例
obj = Child()
obj.feature()
# Initializing Child
# Initializing ParentA
# Initializing ParentB
# Starting Child feature
# Feature from ParentA
# Finishing Child feature# 應用五:修改繼承結構
class Grandparent:def __init__(self):print("Initializing Grandparent")def greet(self):print("Hello from Grandparent")
class ParentA(Grandparent):def __init__(self):print("Initializing ParentA")super().__init__() # 調用Grandparent的__init__方法def greet(self):print("Hello from ParentA")super().greet() # 調用Grandparent的greet方法
class ParentB(Grandparent):def __init__(self):print("Initializing ParentB")super().__init__() # 調用Grandparent的__init__方法def greet(self):print("Hello from ParentB")super().greet() # 調用Grandparent的greet方法
class Child(ParentA, ParentB):def __init__(self):print("Initializing Child")super().__init__() # 這將調用ParentA的__init__,因為ParentA在MRO中排在前面def greet(self):print("Hello from Child")super().greet() # 這將首先調用ParentA的greet,然后是Grandparent的greet(如果ParentA中沒有再次調用super())
# 使用示例
child = Child()
child.greet()
# Initializing Child
# Initializing ParentA
# Initializing ParentB
# Initializing Grandparent
# Hello from Child
# Hello from ParentA
# Hello from ParentB
# Hello from Grandparent# 應用六:框架和庫開發
class PluginBase:def __init__(self):print("Initializing PluginBase")def activate(self):print("Activating PluginBase")self._specific_activation() # 假設有一個特定于插件的激活方法def _specific_activation(self):# 這是一個預期被子類覆蓋的方法raise NotImplementedError("Subclasses must implement this method")
class PluginA(PluginBase):def __init__(self):super().__init__() # 調用父類的初始化方法print("Initializing PluginA")def _specific_activation(self):# 實現特定于PluginA的激活邏輯print("Activating PluginA specific functionality")
class PluginB(PluginBase):def __init__(self):super().__init__() # 調用父類的初始化方法print("Initializing PluginB")def _specific_activation(self):# 實現特定于PluginB的激活邏輯print("Activating PluginB specific functionality")
# 框架的某部分,負責插件的管理和激活
class PluginManager:def __init__(self):self.plugins = []def register(self, plugin):self.plugins.append(plugin)def activate_all(self):for plugin in self.plugins:plugin.activate() # 調用插件的激活方法
# 使用示例
manager = PluginManager()
manager.register(PluginA())
manager.register(PluginB())
manager.activate_all() # 這將激活所有注冊的插件
# Initializing PluginBase
# Initializing PluginA
# Initializing PluginBase
# Initializing PluginB
# Activating PluginBase
# Activating PluginA specific functionality
# Activating PluginBase
# Activating PluginB specific functionality# 應用七:設計模式實現
# 定義一個抽象類,其中包含模板方法和一些具體方法
class AbstractClass:# 模板方法,定義了算法框架def template_method(self):# 調用第一個具體方法self.specific_method1()# 調用鉤子方法(可以被子類覆蓋)self.hook_method()# 調用第二個具體方法self.specific_method2()# 第一個具體方法def specific_method1(self):print("Executing specific method 1 from AbstractClass")# 第二個具體方法def specific_method2(self):print("Executing specific method 2 from AbstractClass")# 鉤子方法,默認不執行任何操作,但可以被子類覆蓋def hook_method(self):pass
# 定義一個繼承自AbstractClass的類ConcreteClassA
class ConcreteClassA(AbstractClass):# 覆蓋父類的第一個具體方法def specific_method1(self):# 首先調用父類的實現(如果需要的話)super().specific_method1()# 然后執行自己的實現print("Executing specific method 1 from ConcreteClassA")# 覆蓋父類的鉤子方法def hook_method(self):print("Executing hook method from ConcreteClassA")
# 定義一個繼承自AbstractClass的類ConcreteClassB
class ConcreteClassB(AbstractClass):# 覆蓋父類的第二個具體方法def specific_method2(self):# 首先調用父類的實現(如果需要的話)super().specific_method2()# 然后執行自己的實現print("Executing specific method 2 from ConcreteClassB")
# 創建ConcreteClassA的實例a
a = ConcreteClassA()
# 調用模板方法,按照算法框架執行
a.template_method()
# 創建ConcreteClassB的實例b
b = ConcreteClassB()
# 調用模板方法,按照算法框架執行
b.template_method()
# Executing specific method 1 from AbstractClass
# Executing specific method 1 from ConcreteClassA
# Executing hook method from ConcreteClassA
# Executing specific method 2 from AbstractClass
# Executing specific method 1 from AbstractClass
# Executing specific method 2 from AbstractClass
# Executing specific method 2 from ConcreteClassB
1-2、VBA:
略,待后補。
2、推薦閱讀:
2-1、Python-VBA函數之旅-callable()函數
Python算法之旅:Algorithms
Python函數之旅:Functions