Python面向对象编程:合集篇(类、对象、封装、继承和多态) 您所在的位置:网站首页 属于面向对象的程序设计语言是 Python面向对象编程:合集篇(类、对象、封装、继承和多态)

Python面向对象编程:合集篇(类、对象、封装、继承和多态)

2024-07-10 17:01| 来源: 网络整理| 查看: 265

Python语言设计之初,就是为了面向对象。所以Python的面向对象更加易于理解。如果你以前学过Java、C++你大概就懂得什么是面向对象,但如果你是第一门编程语言就选择Python,那么也不要害怕。这篇文章,我们将会尽量详细的讲解,把Python面向对象编程的知识讲清楚。

接下来我们先来简单的了解下面向对象的一些基本特征。

 1. 什么是面向对象编程(OOP)?

面向对象编程(Object-Oriented Programming,OOP)是一种程序设计范式,它以对象为中心,将数据和操作数据的方法(函数)组合到一个单元中,这个单元就是对象。每个对象都是类的一个实例,而类则定义了对象的属性(数据)和方法(代码)。换句话说,面向对象编程将现实世界中的实体抽象为程序中的对象,这些对象可以相互交互、传递消息,并且可以继承和扩展。

面向对象编程通常具有以下几个核心概念:

类(Class):定义了对象的模板,包括数据和方法。对象(Object):类的实例,具有特定的属性和方法。封装(Encapsulation):将数据(属性)和操作数据的方法(函数)封装到对象中,使得对象的内部细节对外部不可见。继承(Inheritance):允许一个类(子类)继承另一个类(父类)的属性和方法,并且可以添加自己的特定属性和方法。多态(Polymorphism):允许不同类的对象对同一个方法做出不同的响应,提高代码的灵活性和可重用性。 很好,上面的概念,你已经云里雾里了。那么下面我们简单来讲一下。

一个简单的例子:

假设我们要模拟一个动物园中的动物。我们可以使用定义一个 Animal(动物)类,并创建具体的动物对象。这就是面向对象编程的两个概念了,类、对象。

# 定义 Animal(动物)类 class Animal: def __init__(self, name, age): self.name = name self.age = age def make_sound(self): pass # 定义具体的动物类:猫(Cat)和狗(Dog) class Cat(Animal): def make_sound(self): return "Meow" class Dog(Animal): def make_sound(self): return "Woof" # 创建动物对象 cat1 = Cat("Kitty", 3) dog1 = Dog("Buddy", 5) # 调用动物对象的方法 print(cat1.name, "says:", cat1.make_sound()) # 输出:Kitty says: Meow print(dog1.name, "says:", dog1.make_sound()) # 输出:Buddy says: Woof

上面的代码,我们一步步来说:

第一步:首先定义了一个 Animal(动物)类,它有两个属性 name(名字)和 age(年龄)。在 __init__ 构造函数中,我们初始化了这两个属性。

第二步:Animal 类有一个 make_sound(发出声音)方法,但在基类中我们只定义了方法的签名,没有具体的实现。这是因为我们无法确定所有动物的叫声,具体的叫声会在子类中实现。

第三步:然后我们定义了两个具体的动物类 Cat(猫)和 Dog(狗),它们都继承自 Animal 类。这意味着 Cat 和 Dog 类会继承 Animal 类的属性和方法,并且可以根据需要添加自己的属性和方法。

第四步:在 Cat 类和 Dog 类中,我们重写了 make_sound 方法,分别返回了猫和狗的叫声

第五步:最后,我们创建了两个具体的动物对象 cat1 和 dog1,分别是一只名叫 "Kitty" 的猫和一只名叫 "Buddy" 的狗。

第六步:我们调用了这两个动物对象的 make_sound 方法,并打印出它们的名字和叫声。

 

上面总共讲了6步,6步里面涉及到了:类(Class)、对象(Object)、封装(Encapsulation)、继承(Inheritance)、多态(Polymorphism)。这些概念,具体怎么看呢?往下看:

类:Animal、Cat、Dog 分别是类,它们定义了对象的模板,包括属性和方法。对象:cat1 和 dog1 是 Cat 和 Dog 类的对象,它们是具体的实例,具有特定的属性和方法。封装:每个动物对象封装了自己的属性 name 和 age,并且调用了自己的 make_sound 方法。继承:Cat 和 Dog 类继承了 Animal 类的属性和方法,避免了重复定义。多态:make_sound 方法在不同的子类中表现出不同的行为,根据对象的类型返回不同的叫声。 那么,你现在将这些概念,一个个对应到前面的六步中去,你就大概明白了。明白个大概也行!

下面接着讲.......

 

2. 类和对象

让我们以一个仍然用上面的例子来说明什么是类和对象。我们创建了一个"动物"(Animal)类,然后创建该类的对象,比如"狗"(Dog)和"猫"(Cat)。

2.1 类的定义和创建

我们可以定义一个"动物"(Animal)类,该类具有一些基本属性(如名称和年龄),以及一些行为(如发出声音)。

class Animal: def __init__(self, name, age): self.name = name self.age = age def make_sound(self): pass # 此处留空,因为这是一个抽象的动作,每种动物发出的声音不同,后续会在子类中实现

在这个类中,我们定义了一个构造函数 __init__(),它接收 name 和 age 作为参数,并将它们分配给对象的属性。我们还定义了一个 make_sound() 方法,但目前它什么也不做,因为每种动物发出的声音都不同,所以我们会在子类中覆盖这个方法。

2.2 对象的创建和使用

现在,让我们创建具体的动物对象,比如一个狗对象和一个猫对象,并使用它们的属性和方法。

class Dog(Animal): def make_sound(self): return "Woof!" class Cat(Animal): def make_sound(self): return "Meow!" # 创建狗对象和猫对象 my_dog = Dog("Buddy", 3) my_cat = Cat("Whiskers", 5) # 访问对象的属性 print(f"My dog's name is {my_dog.name} and it is {my_dog.age} years old.") print(f"My cat's name is {my_cat.name} and it is {my_cat.age} years old.") # 调用对象的方法 print(f"My dog says: {my_dog.make_sound()}") print(f"My cat says: {my_cat.make_sound()}") 2.3 类和对象的关系

在这个例子中,Animal 是一个基类(父类),它定义了动物的基本属性和方法。然后,Dog 和 Cat 是 Animal 类的子类(也可以称为派生类),它们继承了 Animal 类的属性和方法,并且还可以定义自己独特的属性和方法。

当我们创建 my_dog 和 my_cat 时,实际上是在内存中实例化了两个对象,每个对象都有自己的 name 和 age 属性,并且可以调用 make_sound() 方法。

类是对对象的抽象,它定义了对象的属性和方法。 对象是类的实例,它具体化了类的定义,并可以执行类中定义的操作。

类和对象之间的关系就像是模具和制造出的产品之间的关系:模具定义了产品的形状和特性,而产品则是模具的具体实例。

 

2.4 属性和方法 2.4.1 实例属性和类属性 实例属性:实例属性是指属于特定实例的属性。它们在创建实例时被赋予,并且每个实例都可以有不同的值。通常在类的 __init__ 方法中初始化。 class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year

在这里,make, model, 和 year 就是 Car 类的实例属性。

类属性:属于类本身的属性,被所有类的实例共享。可以直接在类定义中设置。 class Car: num_cars = 0 # 类属性 def __init__(self, make, model, year): self.make = make self.model = model self.year = year Car.num_cars += 1 # 每创建一个实例,num_cars 加一

在这里,num_cars 就是 Car 类的类属性,它被所有 Car 类的实例共享。

2.4.2 实例方法和类方法 实例方法:操作实例属性的方法,第一个参数通常是 self,代表对象本身。可以访问实例属性,并且可以改变实例的状态。 class Car: def __init__(self, brand): self.brand = brand self.speed = 0 def accelerate(self, amount): self.speed += amount def brake(self, amount): self.speed -= amount car1 = Car("Toyota") print(car1.speed) # 输出: 0 car1.accelerate(50) print(car1.speed) # 输出: 50 car1.brake(20) print(car1.speed) # 输出: 30

accelerate 、brake 就是 Car 类的实例方法,用于打印汽车信息。

类方法:操作类属性的方法,使用 @classmethod 装饰器定义,第一个参数通常是 cls,代表类本身。可以访问类属性,并且可以在整个类上执行操作。 class Dog: num_of_dogs = 0 def __init__(self, name): self.name = name Dog.num_of_dogs += 1 @classmethod def get_num_of_dogs(cls): return cls.num_of_dogs dog1 = Dog("Buddy") dog2 = Dog("Max") print(Dog.get_num_of_dogs()) # 输出: 2

get_num_of_dogs 就是 Dog 类的类方法,用于显示狗总数。

 

2.4.3 静态方法 静态方法:不操作实例属性或类属性的方法,使用 @staticmethod 装饰器定义。它们与类无关,不传递 self 或 cls 参数。可以在类中定义,但是不能访问 self 或 cls。 class Math: @staticmethod def add(x, y): return x + y result = Math.add(5, 10) print(result) # 输出: 15

add 就是 Math 类的静态方法,提供关于类的一般信息。

以上是关于Python中类(Class)、对象(Object)以及属性和方法的基本概念。希望对你的理解有帮助。

 

 封装、继承和多态作为Python面向对象编程(OOP)三个核心概念,它们是面向对象程序设计的基石,允许我们以更加模块化、可维护的方式编写代码。下面我们一起来学习。

 

3. 封装 (Encapsulation)

​封装是指将数据(属性)和操作数据的方法(方法)捆绑在一起的机制。在封装中,对象的内部细节被隐藏起来,只有特定的方法才能访问和操作这些细节。这有助于确保数据的安全性和代码的可维护性。

封装具有以下优势:

优势描述安全性隐藏对象的实现细节,防止外部直接访问和修改对象的内部状态,从而保护数据的安全性。简化调用使用者无需了解对象的内部实现细节,只需知道如何使用对象提供的接口即可。这简化了调用对象的过程,降低了使用的复杂度。降低耦合度封装使得对象的内部改变不会影响到外部的代码。对象的内部细节可以自由改变,而不会影响到使用该对象的其他部分。提高代码的可维护性封装使得代码模块化,每个模块都有清晰的功能和接口。当需要修改代码时,可以更容易地定位和修改相关的部分。   3.1 如何实现封装?

封装可以通过访问控制和访问修饰符来实现。主要有两种访问修饰符:公有属性和方法、私有属性和方法。

公有属性和方法 (Public Attributes and Methods)

可以被类的外部访问。在 Python 中,默认情况下,类的所有属性和方法都是公有的。

class Person: def __init__(self, name, age): self.name = name # 公有属性 self.age = age # 公有属性 def get_name(self): return self.name # 公有方法 # 使用公有属性和方法 person1 = Person("Tiyong", 30) print(person1.name) # 输出: Tiyong print(person1.get_name()) # 输出: Tiyong

在这个例子中,Person类有一个公有方法 get_name(),那么其他类或代码可以通过调用这个方法来获取对象的名称。同样,有一个公有属性 age,那么其他类或代码可以直接访问和修改这个属性。所以,我们的实例对象就可以访问公共的属性和方法。

私有属性和方法 (Private Attributes and Methods)

只能在类的内部访问,外部无法直接访问。在 Python 中,可以在属性名或方法名前加上双下划线 ‘__’ 来定义私有属性和方法。

class Person: def __init__(self, name, age): self.__name = name # 私有属性 self.__age = age # 私有属性 def __display_info(self): return f"Name: {self.__name}, Age: {self.__age}" # 私有方法 # 外部无法直接访问私有属性和方法 person1 = Person("TiYong", 25) # print(person1.__name) # 这会引发错误,因为__name是私有属性 # print(person1.__display_info()) # 这会引发错误,因为__display_info()是私有方法

在上面的例子中:person1对象就不能访问__name私有属性和__display_info()私有方法。

尽管外部无法直接访问私有属性和方法,但我们仍然可以通过公有方法来间接访问和操作它们。这种间接访问的方式使得我们可以控制对象的状态和行为,确保数据的一致性和安全性。

class Person: def __init__(self, name, age): self.__name = name # 私有属性 self.__age = age # 私有属性 def get_name(self): return self.__name # 公有方法 def set_name(self, new_name): self.__name = new_name # 公有方法,用于修改私有属性 def display_info(self): return f"Name: {self.__name}, Age: {self.__age}" # 公有方法 # 通过公有方法访问和修改私有属性 person1 = Person("TiYong", 30) print(person1.get_name()) # 输出: TiYong person1.set_name("Toy") print(person1.display_info()) # 输出: Name: Toy, Age: 30

那么,封装通过隐藏对象的内部细节、定义清晰的接口,提高了代码的安全性、可维护性和复用性,这就使得我们的程序更加健壮和易于开发与维护了。

 

4. 继承(Inheritance)

继承就是允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。子类可以继承父类的特性,并且可以在此基础上添加自己的新特性。这种机制允许代码的重用和层次化的设计。继承,就是字面上意思,继承。

4.1 继承的类型 4.1.1 单继承

单继承是指一个子类只能继承一个父类的属性和方法。这是最简单和最常见的继承类型。

class ParentClass: def parent_method(self): print("Parent method") class ChildClass(ParentClass): def child_method(self): print("Child method") # 子类继承父类的方法 child = ChildClass() child.parent_method() # 输出: Parent method child.child_method() # 输出: Child method 4.1.2 多继承

多继承是指一个子类可以同时继承多个父类的属性和方法。这使得子类可以具有多个父类的特性,但也可能引发一些复杂性和歧义。

class ParentClass1: def method1(self): print("Method 1 from ParentClass1") class ParentClass2: def method2(self): print("Method 2 from ParentClass2") class ChildClass(ParentClass1, ParentClass2): def child_method(self): print("Child method") # 子类继承多个父类的方法 child = ChildClass() child.method1() # 输出: Method 1 from ParentClass1 child.method2() # 输出: Method 2 from ParentClass2 child.child_method() # 输出: Child method 4.1.3 Python的继承顺序(MRO)

在多继承的情况下,Python 使用 C3 线性化算法来确定方法解析顺序(Method Resolution Order, MRO)。MRO 定义了类的方法解析顺序,确保在继承链中查找方法时,按照一定的顺序进行搜索。

可以通过调用类的 mro() 方法来查看方法的解析顺序:

print(ChildClass.mro()) # 输出: [, , , ]

 

4.2 继承的优势

继承允许子类重用父类的代码,避免了重复编写相同的代码片段。子类可以直接使用父类已经定义的方法和属性。

优势描述代码重用子类可以直接使用父类已经定义的方法和属性,避免了重复编写相同的代码片段。可扩展性子类可以在不修改父类的情况下,添加新的属性和方法,从而使得代码更具可扩展性。这样可以在不影响父类的基础上,为程序添加新的功能。

 

4.3 继承的实际应用 4.3.1 创建子类

通过继承可以创建子类,实现代码的重用和层次化的设计。子类可以继承父类的方法和属性,并且可以添加自己的方法和属性。

class Animal: def speak(self): pass class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!" dog = Dog() print(dog.speak()) # 输出: Woof! cat = Cat() print(cat.speak()) # 输出: Meow! 4.3.2 覆盖父类方法(Method Overriding)

子类可以覆盖父类的方法,即在子类中重新定义与父类同名的方法。这样做可以根据子类的需求修改方法的实现。

class Bird: def speak(self): return "Chirp!" class Parrot(Bird): def speak(self): return "Polly wants a cracker!" parrot = Parrot() print(parrot.speak()) # 输出: Polly wants a cracker! 4.3.3 调用父类方法(super() 函数)

子类中可以通过 super() 函数调用父类的方法。这在子类需要扩展父类方法的功能时非常有用。

class Rectangle: def __init__(self, length, width): self.length = length self.width = width def area(self): return self.length * self.width class Square(Rectangle): def __init__(self, side_length): super().__init__(side_length, side_length) # 调用父类的 __init__() 方法 square = Square(5) print(square.area()) # 输出: 25

在上面的例子中,Square 类继承自 Rectangle 类,并通过 super() 函数调用了 Rectangle 类的 __init__() 方法,实现了对正方形的初始化。

以上,就大概是继承的内容了。

 

5. 多态(Polymorphism)

 

多态是指允许对象在不同的情况下表现出不同的行为。简单地说,多态性意味着相同的方法调用可能会有不同的实现方式,具体取决于调用该方法的对象的类型或类的实现。

5.1 多态的实现方式 5.1.1 方法重写(Method Overriding)

方法重写是实现多态的一种方式,它允许子类覆盖(重写)父类的方法,以便在子类中实现特定的行为。当子类重新定义了与父类同名的方法时,调用这个方法时会执行子类的实现。通过一个例子展示方法重写:

class Animal: def speak(self): raise NotImplementedError("Subclass must implement abstract method") class Dog(Animal): def speak(self): return "Woof!" class Cat(Animal): def speak(self): return "Meow!" # 多态性的体现 def animal_sound(animal): return animal.speak() dog = Dog() cat = Cat() print(animal_sound(dog)) # 输出: Woof! print(animal_sound(cat)) # 输出: Meow!

 

5.1.2 方法重载(Method Overloading)

方法重载是一种在同一个类中,方法名称相同但参数列表不同的技术。但是,在Python中,并没有像其他编程语言那样直接支持方法重载的特性,不过,可以通过一些技巧来模拟。

比如:使用默认参数值或者 *args 和 **kwargs 参数来实现类似方法重载的效果。

class Calculator: def add(self, a, b): return a + b def add(self, a, b, c): return a + b + c calc = Calculator() print(calc.add(2, 3)) # 输出: TypeError: add() missing 1 required positional argument: 'c' print(calc.add(2, 3, 4)) # 输出: 9

 

5.2 多态的优势 优势描述灵活性和可扩展性允许同一个方法有不同的实现方式,使得代码更加灵活和可扩展。当需要添加新的功能时,只需添加新的子类或覆盖现有方法,而不需要修改现有代码。代码简洁性可以编写更加简洁和清晰的代码。通过使用多态性,可以将相同的操作应用于不同类型的对象,从而减少了重复代码的编写。 5.3 多态的实际应用 5.3.1 多态的实例

多态在实际应用中非常多。

class Shape: def draw(self): pass class Circle(Shape): def draw(self): return "Drawing Circle" class Square(Shape): def draw(self): return "Drawing Square" # 多态性的体现 def draw_shape(shape): return shape.draw() circle = Circle() square = Square() print(draw_shape(circle)) # 输出: Drawing Circle print(draw_shape(square)) # 输出: Drawing Square

例子,展示了在图形绘制中,不同的图形对象可以有不同的 draw 方法实现,但可以使用相同的方式进行绘制。Shape 是一个基类,Circle 和 Square 是它的子类,它们都有自己的 draw 方法实现。在调用 draw_shape 函数时,根据传入的参数不同,会执行不同子类的 draw 方法。

 

5.3.2 使用抽象基类(Abstract Base Classes)

abc 模块,可以通过抽象基类定义抽象方法,从而强制子类实现这些方法,实现接口的规范化。

from abc import ABC, abstractmethod class Shape(ABC): @abstractmethod def draw(self): pass class Circle(Shape): def draw(self): return "Drawing Circle" class Square(Shape): def draw(self): return "Drawing Square" # 多态性的体现 def draw_shape(shape): return shape.draw() # 抽象基类确保子类实现了抽象方法 # rectangle = Shape() # 会引发错误,因为 Shape 是抽象基类,不能实例化 circle = Circle() square = Square() print(draw_shape(circle)) # 输出: Drawing Circle print(draw_shape(square)) # 输出: Drawing Square

在这个例子中,Shape 是一个抽象基类,定义了一个抽象方法 draw,所有继承自 Shape 的子类必须实现 draw 方法。这样可以确保所有的子类都有相同的接口,实现了多态的规范化。

通过上面的介绍,我们知道了多态使得代码更加灵活、可扩展、简洁。这也就是为什么面向对象那么受欢迎的原因了。

 

6. 实例展示

最后,我们通过两篇文章的学习,现在,我们通过实例代码来回顾一下所有的内容。

6.1 创建一个简单的封装类

示例: 定义一个 Car 类,封装汽车的属性和方法。

class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year def __str__(self): return f"汽车信息:\n 品牌:{self.make}\n 型号:{self.model}\n 年份:{self.year}" def start(self): print(f"{self.make} {self.model} 已启动!") car = Car("Toyota", "Camry", 2024) print(car) car.start()

输出如下:

汽车信息: 品牌:Toyota 型号:Camry 年份:2024 Toyota Camry 已启动! 6.2 实现一个继承的示例

示例: 定义一个 ElectricCar 类,继承 Car 类并添加续航里程属性和方法。

# 定义Car类 class Car: def __init__(self, make, model, year): self.make = make self.model = model self.year = year def __str__(self): return f"汽车信息:\n 品牌:{self.make}\n 型号:{self.model}\n 年份:{self.year}" def start(self): print(f"{self.make} {self.model} 已启动!") # 继承Car class ElectricCar(Car): def __init__(self, make, model, year, range): super().__init__(make, model, year) self.range = range def __str__(self): return f"{super().__str__()}\n 续航里程:{self.range}公里" electric_car = ElectricCar("Tesla", "Model 3", 2024, 600) print(electric_car)

输出如下:

汽车信息: 品牌:Tesla 型号:Model 3 年份:2024 续航里程:600公里 6.3 演示多态的用例

示例: 定义一个 Vehicle 类,包含 drive() 方法,并定义 Car 和 Bicycle 两个子类,分别实现不同的 drive() 方法。

class Vehicle: def drive(self): raise NotImplementedError # 多态重写 class Car(Vehicle): def drive(self): print("驾驶汽车...") class Bicycle(Vehicle): def drive(self): print("骑自行车...") car = Car() bicycle = Bicycle() vehicles = [car, bicycle] for vehicle in vehicles: vehicle.drive()

输出如下:

驾驶汽车... 骑自行车...

 

总结

类、对象、封装、继承和多态的重要性总结如下表:

概念描述重要性类一种抽象数据类型,用于描述一组具有相同属性和方法的对象。提高代码的组织性和可维护性,提高代码的复用性。对象类的实例,包含了类所定义的所有属性和方法。提高代码的组织性和可维护性,提高代码的复用性。封装将对象的属性和方法隐藏在类中,对外只提供接口进行访问。提高代码的安全性,提高代码的可维护性。继承允许子类继承父类的属性和方法的一种机制。提高代码的复用性,提高代码的可扩展性。多态同一个方法可以对不同类型的对象执行不同的操作。提高代码的灵活性,提高代码的可扩展性。

一些概念需要你记住的:

使用 class 关键字定义类。使用 __init__ 方法初始化对象的属性。使用 self 关键字引用当前对象。使用 super() 函数调用父类的方法。使用 isinstance() 函数检查对象的类型。

 

这里,我们已经讲完了Python面向对象的知识:类(Class)、对象(Object)、封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)。掌握这些知识,可以帮助你编写出更优雅、更易读、更可维护的 Python 代码。

欢迎大家和我一起继续学习、记录python的下一个知识点。

如果感觉阅读对您还有些作用,可以评论留言,关注我。谢谢您的阅读!

 往期学习:

Python安装教程(版本3.8.10)windows10

Linux系统:安装Conda(miniconda)

Conda快速安装的解决方法(Mamba安装)

VSCode安装教程(版本:1.87.0)Windows10

Python基础语法:从入门到精通的必备指南

Python的基本数据类型

Python数据类型间的转换(隐式、显式)-CSDN博客

Python基础知识:运算符详解-CSDN博客

Python基础知识:数字类型及数学函数详解-CSDN博客

Python字符串操作及方法详解!一篇就搞定!-CSDN博客

Python列表及其操作详解,从此不再迷茫!-CSDN博客

Python元组(Tuple)深度解析!

Python字典的使用技巧(一篇详解)

Python条件控制深度解析,成为编程必备

Python循环语句全解析(附实战演练)

Python函数高效编程技巧,提升你的代码效率!

Python模块和包全解析,一篇文章就够!

Python lambda(匿名函数),一文详解

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有