Python-VBA函数之旅-super函数

news2024/10/4 10:20:08

目录

一、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的类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

个人主页: https://myelsa1024.blog.csdn.net/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1669893.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JS解密之新js加密实战(二)

前言 上次发了一篇关于新加密的,只解了前边两层,这中间家里各种事情因素影响,没有继续进一步研究,今天百忙之中抽空发布第二篇,关于其中的一小段加密片段,我认为分割成多个小片段是更容易被理解的。逻辑相…

【SRC实战】修改赠送金额支付漏洞

挖个洞先 https://mp.weixin.qq.com/s/NQKJQF81XpG8815EfgvgKw “ 以下漏洞均为实验靶场,如有雷同,纯属巧合 ” 01 — 漏洞证明 “ 充值赠送金额能否修改? ” 1、充值30元赠送1.9元礼包,充值100元赠送7元礼包,充值…

买卖股票的最佳时机 II(LeetCode 122)

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…

FANUC机器人单轴零点标定时提示无法执行零点标定,由于重力补偿已启用,所有机器人轴的脉冲计数必须有效

FANUC机器人单轴零点标定时提示无法执行零点标定,由于重力补偿已启用,所有机器人轴的脉冲计数必须有效 首先,机器人由于长时间断电未使用,6个轴的编码器数据全部丢失,上电后报警SRVO-062, 有关SRVO-062故障报警的相关内容可参考以下链接: FANUC机器人SRVO-062报警原因分…

通过集成式 PLM Services for SIMULIA 实现协作

在快速发展的产品开发世界中,无缝和高效的管理解决方案已成为必需品。在这些解决方案中,PLM 服务正变得越来越普及,这要归功于它们的能力。这些服务提供了一种管理产品生命周期的集成方法,从概念开始,到设计和制造&…

Pyhton专题学习资料包,Python从入门到精通全套学习资料[30G]

资源概览 百本Python学习书籍大礼包百本前端学习书籍大礼包微专业-数据挖掘分析之Python篇小甲鱼零基础入门学习Python(全96集) 资源获取 🧑‍💻【Pyhton专题资料】【30G】 百本Python书籍## 百本前端书籍 微专业-数据挖掘分析之Python篇 预备课【先…

Docker下Open WebUI,Ollama的安装实践

提示一下Open WebUI与ollama的关系。后端的同学可以理解为Open WebUI等于是个Navicat,Ollama就是具体的数据库实例。 官方安装文档: 🏡 Home | Open WebUI Open WebUI官网文档翻译: 注意: 使用Docker安装Open WebU…

有趣的css - 打字机动画效果

大家好,我是 Just,这里是「设计师工作日常」,今天分享的是使用 css 实现好玩的单行打字机效果,和我一起看看吧。 《有趣的css》系列最新实例通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html 代码css 部分代码 完整…

成员函数构造函数析构函数

文章目录 类的6个默认成员函数构造函数概述定义特性 析构函数概述特性 类的6个默认成员函数 空类: 如果一个类里面什么都没有写,我们称之为空类 class Date {};空类真的什么都没有吗? 实际上并非如此,编译器会自动生成6个默认成…

樊春海院士/姚广保课题组2024年博士后/助理研究员火热招募!

尊敬的读者们,我们很高兴地向您介绍一个激动人心的机会——上海交通大学张江高等研究院正在进行博士后和科研助理的招聘,这是一个与顶尖科学家共事、参与前沿科学研究的绝佳机会。 工作地点位于风景优美、充满活力的上海市浦东新区,这里是中国…

FENDI CLUB精酿啤酒馆与传统啤酒销售模式的不同

精酿啤酒火了,国产品牌精酿也在迅速崛起,为精酿啤酒这一小众品类发展加足了马力。与此同时,精酿酒吧、精酿小酒馆也开始出现了增长。这标志着中国精酿啤酒市场的快速发展和国产品牌的崭新局面。 FENDI CLUB精酿啤酒已经在不少地方开始积极开…

CDGA|数据治理实战案例:从数据收集到治理,再到价值应用

在当今信息爆炸的时代,数据治理已成为企业提升核心竞争力、实现数字化转型的关键一环。本文将通过一个实战案例,详细剖析数据治理的全过程,从数据收集到治理,再到价值应用,为读者提供有益的参考和启示。 数据收集&…

港中深「户外自重构蜗牛机器人集群」登Nature子刊!

在科幻电影《超能陆战队》中,我们见证了一种由成千上万个微小磁性单元组成的机器人通过磁力相互连接,形成各种复杂的三维结构。香港中文大学(深圳)林天麟教授团队致力于将这一科幻转化为现实,近年来开发了一系列自由形…

APP反抓包 - 客户端证书验证

一,校验的原理 下图为HTTP协议的请求过程:传输过程中都是明文数据 下图为HTTPS协议的请求过程: 注意:公钥加密的数据只能通过对应的私钥才能解密,就算是进行加密的公钥也不能进行解密。 上述的请求过程看似复杂,实际就是两部分: 通过公钥与私钥同步对称密钥使用对…

安科瑞工业IT产品及解决方案—电源不接地,设备外壳接地【监测系统对地绝缘电阻】

低压配电系统分类及接地保护方案 国际电工委员会(iec)对各接地方式供电系统的规定规定:(低压:交流1000V以下) 低压配电接地、接零系统分为IT、TT、TN三种基本形式。TN分为TN-C,TN-S,TN-C-S三种…

网络编程UDP

目录 1.什么是网络编程 1.1发送端和接收端 1.2请求和响应 1.3客户端和服务端 1.4常见的客户端服务端模型 2.Socket套接字 2.1Socket概念 2.2三种Socket套接字分类 3.Java数据报套接字通信模型(UDP) 4.Socket编程注意事项 5.UDP数据报套接字编程…

只需三步,教你轻松搞定内网穿透

最近开发过程中又遇到了需要外网访问内部服务接口的需求,比如调用三方服务的各种回调通知、支付成功回调、大模型回调等都需要外部服务器来访问内部的接口,这里有个问题就是如果我们在本地或者测试环境调试的过程中我们使用的是内网环境,那外…

【数据结构课程学习】:队列学习

🎁个人主页:我们的五年 🔍系列专栏:数据结构课程学习 🌷追光的人,终会万丈光芒 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 🚗 1.队列的基本概念&#xff1a…

AI地名故事:笔岗村

笔岗村,实际上是由笔村和宏岗村两个古老的村落合并而成的。南宋度宗元年,也就是公元1265年,笔村开始建立。随着时间的推移,到了宋代后期,宏岗村也相继建立。这两个村落各自承载着丰富的历史和文化,最终在历…

(五)STM32F407 cubemx IIC驱动OLED(2)硬件篇

这篇文章主要是个人的学习经验,想分享出来供大家提供思路,如果其中有不足之处请批评指正哈。   废话不多说直接开始主题,本人是基于STM32F407VET6芯片,但是意在你看懂这篇文章后,不管是F1,F4,H7等一系列系统硬件IIC配…