当前位置: 首页 > news >正文

Python——类和对象、继承和组合

类和对象

Python中的类和对象是面向对象编程(OOP)的核心概念。面向对象编程是一种编程范式,它使用“对象”来设计软件。对象具有状态(即属性)和行为(即方法)。类是用于创建对象的蓝图或模板。

类(Class)

类是一个用户定义的类型,它定义了对象的属性(数据)和方法(函数)。类是创建对象(也称为类的实例)的模板。

定义类

在Python中,使用class关键字来定义一个类。类的定义包括类名和类的体(缩进块),其中类的体可以包含属性(变量)和方法(函数)。

class MyClass:  # 类属性(通常是静态属性,用于所有实例共享的数据)  # 但通常我们定义在__init__中的是实例属性  # 初始化方法,特殊方法__init__,用于创建对象时初始化对象的属性  def __init__(self, name, age):  self.name = name  # 实例属性  self.age = age    # 实例属性  # 定义一个方法  def greet(self):  print(f"Hello, my name is {self.name} and I am {self.age} years old.")
  • __init__方法是一个特殊方法,称为类的构造器或初始化方法。当创建类的新实例时,Python会自动调用此方法。
  • self代表类的实例本身,即一个类可能有无数个对象,通过self,类可以知道调用自己的实例对象是哪一个,self用于访问类中的属性和方法。所以类中的每一个方法,第一个参数默认都是self。

构造函数__init__方法

在Python中,构造函数通常指的是初始化方法(__init__ 方法)。这个方法是一个特殊的方法,用于在创建类的新实例时设置对象的初始状态。当你使用类名并传递必要的参数来创建一个新的对象时,__init__ 方法会自动被调用。

这里有一个简单的例子来说明Python中的构造函数(初始化方法)是如何工作的:

class Person:  def __init__(self, name, age):  self.name = name  self.age = age  def greet(self):  print(f"Hello, my name is {self.name} and I am {self.age} years old.")  # 创建一个Person类的实例  
person1 = Person("Alice", 30)  # 调用实例的方法  
person1.greet()  # 输出: Hello, my name is Alice and I am 30 years old.

在这个例子中,Person 类有一个构造函数(__init__ 方法),它接收三个参数:selfname 和 ageself 参数是对类实例本身的引用,用于访问类中的变量和方法。name 和 age 是传递给构造函数的参数,用于初始化新创建的对象的状态。

构造函数(__init__ 方法)的主要目的是初始化新创建的对象的状态。你可以在这个方法内设置任何必要的初始值,或者在对象创建时执行任何必要的设置步骤。

值得注意的是,虽然构造函数在Python中扮演了初始化对象的角色,但它本身并不“返回”对象实例。当你调用类并传递参数时(如 person1 = Person("Alice", 30)),Python会自动处理对象的创建和构造函数的调用,并将新创建的对象引用赋值给左侧的变量(在这个例子中是 person1)。

对象(Object)

对象是类的实例。通过类,我们可以创建具有相同属性和方法的对象。创建对象的过程称为实例化。

创建对象

使用类名后跟一对圆括号(可能包含传递给__init__方法的参数)来创建对象。

# 创建MyClass的实例  
obj1 = MyClass("Alice", 30)  
obj2 = MyClass("Bob", 25)  # 调用对象的方法  
obj1.greet()  # 输出: Hello, my name is Alice and I am 30 years old.  
obj2.greet()  # 输出: Hello, my name is Bob and I am 25 years old.

访问对象的属性和方法

使用点(.)操作符来访问对象的属性和方法。

print(obj1.name)  # 访问属性  
obj1.greet()      # 调用方法

类的特殊方法

Python中有一些特殊的方法,也称为魔术方法或双下划线方法(dunder methods),它们以双下划线开头和结尾。它们为Python类提供了丰富的功能。例如:

  • __init__:构造函数
  • __str__:定义对象的字符串表示形式
  • __repr__:定义对象的“官方”字符串表示形式,通常用于调试
  • __add____sub__等:用于定义对象的算术运算

封装、继承和多态

这三个概念是面向对象编程的三大支柱:

  • 封装:将数据(属性)和操作数据的方法(函数)捆绑在一起,形成一个整体(即类)。
  • 继承:允许我们定义基于另一个类的类,继承其属性和方法。
  • 多态:允许不同类的对象对同一消息作出响应。

继承

Python中的类继承是面向对象编程(OOP)的一个核心概念,它允许我们定义一个类(子类或派生类)来继承另一个类(父类或基类)的属性和方法。继承是代码复用的一种重要方式,它使得我们可以基于现有的类来构建新的类,而无需从头开始编写所有的代码。

继承的基本语法

在Python中,继承是通过在类定义时指定一个或多个父类来实现的。父类名被放在类定义语句的圆括号中。如果未指定父类,则默认继承自object类(Python 3.x中所有类的最终基类)。

class ParentClass:  # 父类定义  pass  class ChildClass(ParentClass):  # 子类定义,继承自ParentClass  pass

继承的特性

  1. 属性继承:子类会继承父类的所有非私有属性(即不以双下划线开头的属性)。但是,如果子类定义了与父类同名的属性,则子类属性会覆盖父类属性。

  2. 方法继承:子类会继承父类的所有方法(包括特殊方法,如__init__)。但是,子类可以重写(或称为覆盖)这些方法,以提供特定的实现。

  3. 构造器继承:子类会继承父类的__init__方法,但通常需要在子类中重写它,以初始化子类特有的属性。如果子类没有重写__init__方法,并且需要初始化父类属性,则需要在子类的其他方法中显式调用父类的__init__方法(使用super()函数或父类名直接调用)。

使用super()函数

super()函数返回了一个代表父类的临时对象,允许你调用父类的方法。这在子类中重写父类方法时特别有用,因为它允许子类在调用父类方法的同时,还可以添加或修改功能,而不是完全替换父类的方法。

class Parent:  def __init__(self, value):  self.value = value  def show(self):  print(self.value)  class Child(Parent):  def __init__(self, value, child_value):  super().__init__(value)  # 调用父类的__init__方法  self.child_value = child_value  def show(self):  super().show()  # 调用父类的show方法  print(self.child_value)

使用super()的好处

  1. 代码重用:通过调用父类的方法,子类可以重用父类中的代码,而无需重新编写。
  2. 维护性:如果父类的方法发生变化(例如,添加了新的功能或修复了bug),使用 super() 调用该方法的子类也会自动继承这些变化,无需子类修改中的代码。
  3. 多继承:在Python中支持多继承,类super() 可以确保每个父的方法只被调用一次,即使在复杂的继承体系中也能保持方法的正确调用顺序。

多重继承

Python还支持多重继承,即一个类可以继承自多个父类。在类定义时,将多个父类名放在圆括号中,用逗号分隔即可。

class A:  def method_a(self):  print("Method A")  class B:  def method_b(self):  print("Method B")  class C(A, B):  # 类C继承自A和B  pass  c = C()  
c.method_a()  # 调用A类的方法  
c.method_b()  # 调用B类的方法

需要注意的是,多重继承可能会引发一些复杂的问题,如方法解析顺序(Method Resolution Order, MRO)问题,这可能会影响到方法的调用结果。Python使用C3线性化算法来确定MRO,以确保继承体系的一致性和可预测性。

多态

在Python中,多态(Polymorphism)是一种非常自然且广泛使用的特性,它允许一个接口(通常指的是一个方法)被用于不同的类实例,并产生不同的结果。在Python中,多态通常是通过继承(Inheritance)和方法的重写(Overriding)来实现的,但Python的动态类型系统和“鸭子类型”(Duck Typing)原则使得多态的实现更为简单和直观。

鸭子类型(Duck Typing)

Python采用的是“鸭子类型”的动态类型系统。这意味着我们并不显式地声明一个对象所属的类,而是基于它做什么(即它有什么方法和属性)来对待它。只要对象可以执行我们期望的操作(比如调用某个方法),我们就可以把它当作那个类型的对象来用,而不需要关心它实际属于哪个类。这种动态类型系统为Python提供了强大的多态能力。

示例

下面是一个简单的Python示例,展示了多态的实现。

# 定义一个基类  
class Animal:  def speak(self):  raise NotImplementedError("Subclass must implement abstract method")  # 定义两个继承自Animal的子类  
class Dog(Animal):  def speak(self):  return "Woof!"  class Cat(Animal):  def speak(self):  return "Meow!"  # 使用多态  
def make_it_speak(animal):  print(animal.speak())  # 创建对象  
dog = Dog()  
cat = Cat()  # 使用同一个函数处理不同的对象  
make_it_speak(dog)  # 输出: Woof!  
make_it_speak(cat)  # 输出: Meow!

在这个例子中,make_it_speak函数接受一个Animal类型的参数,但实际上它可以接受任何具有speak方法的对象。无论是Dog对象还是Cat对象,只要它们实现了speak方法,就可以被make_it_speak函数处理,这就是多态的体现。

注意

  • Python没有像一些其他语言(如Java或C++)那样的显式接口声明。Python中的“接口”通常是通过约定(即所有实现该接口的类都必须有相同的方法名)来隐式实现的。
  • NotImplementedError在这个例子中被用作一个标记,表明这个方法是抽象的,应该在子类中实现。但这并不是Python强制要求的,它只是一个良好的编程实践。
  • Python的动态类型系统和鸭子类型原则使得多态在Python中非常自然和强大。你不需要显式地声明类型,只需要确保对象有正确的方法即可。

组合

在Python中,组合(Composition)是一种将对象作为另一个对象的属性来使用的技术。这是面向对象编程(OOP)中的一个核心概念,它允许你通过组合现有的类来构建更复杂的类。组合强调了一种“有一个”(has-a)的关系,即一个类包含另一个类的对象作为其属性。

组合与继承不同。继承是“是一个”(is-a)的关系,它允许子类继承父类的属性和方法。而组合则更侧重于将对象作为另一个对象的组件或部分来使用,以实现更复杂的结构和功能。

组合的例子

假设我们有两个类:Car(汽车)和Engine(发动机)。一个汽车有一个发动机,这就是一个典型的组合关系。

class Engine:  def __init__(self, horsepower):  self.horsepower = horsepower  def start(self):  print(f"Engine starts with {self.horsepower} horsepower.")  class Car:  def __init__(self, make, model, engine):  self.make = make  self.model = model  self.engine = engine  # Car类组合了一个Engine对象  def start_car(self):  self.engine.start()  # 调用Engine对象的start方法  # 使用组合  
my_engine = Engine(200)  
my_car = Car("Toyota", "Corolla", my_engine)  
my_car.start_car()  # 输出: Engine starts with 200 horsepower.

在这个例子中,Car类通过其__init__方法接收一个Engine对象作为参数,并将其存储在其实例变量engine中。这样,Car类就“组合”了一个Engine对象。然后,Car类可以通过其start_car方法调用Engine对象的start方法,从而实现了对汽车启动行为的模拟。

组合的优点

  1. 更好的封装:通过组合,你可以将对象封装成更小的、可复用的组件。
  2. 更灵活的设计:组合允许你在运行时动态地改变对象的组合方式,而不需要修改类的定义。
  3. 更清晰的依赖关系:组合明确表达了对象之间的“有一个”关系,使得代码更易于理解和维护。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 软考:软件设计师 — 17.程序设计语言与语言处理程序基础
  • IDEA: Html代码格式化
  • 【基础】Three.js中添加操作面板,GUI可视化调试(附案例代码)
  • Java-多线程IO工具类
  • MySQL入门学习-对系统数据库的常用查询
  • midwayjs 框架使用 rabbitmq 消息延迟
  • ES 根据条件删除文档
  • 【Python入门】第5节 数据容器
  • 分布式云扩展 AI 边缘算力,助力用户智能化创新
  • [Linux#47][网络] 网络协议 | TCP/IP模型 | 以太网通信
  • Apache RocketMQ 中文社区全新升级丨阿里云云原生 7 月产品月报
  • Xor Sigma Problem
  • CSS系列之浮动清除clear(三)
  • 数据库mysql集群主从、高可用MGR、MHA技术详解
  • Go 语言生产服务故障案例精析
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • 2017前端实习生面试总结
  • android图片蒙层
  • FineReport中如何实现自动滚屏效果
  • Git初体验
  • IDEA常用插件整理
  • javascript数组去重/查找/插入/删除
  • Joomla 2.x, 3.x useful code cheatsheet
  • Laravel 实践之路: 数据库迁移与数据填充
  • PHP 的 SAPI 是个什么东西
  • PV统计优化设计
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • vue 配置sass、scss全局变量
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 构造函数(constructor)与原型链(prototype)关系
  • 简单基于spring的redis配置(单机和集群模式)
  • 日剧·日综资源集合(建议收藏)
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 微信开源mars源码分析1—上层samples分析
  • 学习ES6 变量的解构赋值
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (C11) 泛型表达式
  • (day6) 319. 灯泡开关
  • (PADS学习)第二章:原理图绘制 第一部分
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (七)Appdesigner-初步入门及常用组件的使用方法说明
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • *2 echo、printf、mkdir命令的应用
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .gitattributes 文件
  • .NET C# 使用GDAL读取FileGDB要素类
  • .NET Core 成都线下面基会拉开序幕
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .net web项目 调用webService
  • .NET6 命令行启动及发布单个Exe文件
  • .net连接oracle数据库