目录
一、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_attr print(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_attr print(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 = attr1 print(f"Parent1.__init__ called with {attr1}")class Parent2: def __init__(self, attr2): self.attr2 = attr2 print(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_attr print(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的类ConcreteClassAclass 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的类ConcreteClassBclass ConcreteClassB(AbstractClass): # 覆盖父类的第二个具体方法 def specific_method2(self): # 首先调用父类的实现(如果需要的话) super().specific_method2() # 然后执行自己的实现 print("Executing specific method 2 from ConcreteClassB")# 创建ConcreteClassA的实例aa = ConcreteClassA()# 调用模板方法,按照算法框架执行a.template_method()# 创建ConcreteClassB的实例bb = 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