
|----------------|
| 你好,我是安然无虞。 |
文章目录
-
- 面向对象三大特性
-
- [1. 封装](#1. 封装)
- [2. 继承](#2. 继承)
- [3. 多态](#3. 多态)
- [4. 抽象基类](#4. 抽象基类)
- [5. 补充练习](#5. 补充练习)

面向对象三大特性
面向对象编程(Object-Oriented Programming, 简称OOP)有三大特性, 分别是封装 、继承 和多态.这些特性是面向对象编程的基础, 它们使得程序的设计更加灵活、易于维护和扩展.
1. 封装
封装是指将数据和操作数据的方法封装在一个单独的单元中, 对外部隐藏数据的具体实现细节, 只暴露必要的接口供外部访问.
通过封装, 可以实现数据的隐藏和保护, 防止外部直接访问对象的内部数据, 同时还可以控制对数据的修改和操作, 确保数据的有效性和安全性.
封装的优势:
- 提高代码的安全性和可靠性, 外部无法直接修改对象的内部数据, 只能通过定义的接口进行访问和操作.使得对象的数据对外部是不可见的, 提高了数据的安全性和私密性.
- 封装可以将一组数据和操作封装成一个对象, 使得代码更加模块化和可复用.其他部分的代码可以通过调用对象的接口来使用其功能, 无需关心内部的具体实现.
- 封装可以降低代码之间的耦合性. 对象之间通过接口进行通信, 而不是直接访问和修改其内部状态, 这使得代码更加灵活和易于维护.
python
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"大家好, 我的名字叫{self.name}, 今年{self.age}岁")
# 创建实例对象
stu = Student('张三', 18)
stu.name = '李四'
stu.age = 20
print(stu.name)
print(stu.age)
# 李四
# 20
# 这里的实例变量name和age都是公有属性, 类外可以直接访问和修改.
封装的实现
在 Python 中, 封装通过类来实现.将数据和操作封装在一个类中.类定义了对象的属性和方法, 属性表示对象的状态, 方法表示对象的行为.
在 Python 中, 封装并不是强制性的, 所有的属性和方法默认都是公开的, 外部可以直接访问和修改.但是, 可以通过命名约定来约束对属性和方法的访问.通常, 以下命名约定用于指定属性和方法的访问控制:
公有属性和方法: 默认情况下, 类中的属性和方法都是公有的, 它们的名字前都没有下划线, 这类型的属性和方法在类的外部, 内部, 子类中, 都是可以正常访问的.
私有属性和方法 : 以双下划线(__)开头的属性和方法表示为私有的
, 外部不能直接访问.如果外部需要访问或修改这些属性, 应该通过公开的接口方法来实现.
受保护的属性和方法 : 以单下划线(_)开头的属性和方法表示为受保护的
, 外部可以访问, 但是应该将其视为内部实现, 不建议直接访问.
python
class Student:
def __init__(self, name, age):
self.__name = name # 私有属性
self.age = age
def introduce(self):
print(f"大家好, 我的名字叫{self.__name}, 今年{self.age}岁")
# 创建实例对象
stu = Student('张三', 18)
stu.__name = '李四' # 理论上来说类外不能访问和设置私有属性
stu.age = 20
print(stu.__name)
print(stu.age)
# 李四
# 20
# 为什么这里在类外也可以访问和设置私有属性呢?
# 如果我们执行实例方法.introduce():
stu.introduce()
# 大家好, 我的名字叫张三, 今年20岁
# 我们发现类内的数据并没有改变
# 所以上面在类外设置私有变量值, 对类的内部并没有影响.
我们在类外使用和设置类内的私有属性需要通过类内的公有方法:
python
class Student:
def __init__(self, name, age):
self.__name = name
self.__age = age
def introduce(self):
print(f"大家好, 我的名字叫{self.__name}, 今年{self.__age}岁")
def get_name(self):
return self.__name
def get_age(self):
return self.__age
def set_name(self, name):
self.__name = name
def set_age(self, age):
self.__age = age
# 创建实例对象
stu = Student('张三', 18)
stu.set_name('李四')
stu.set_age(20)
name = stu.get_name()
age = stu.get_age()
print(name)
print(age)
私有属性的原理:
python
class A:
def __init__(self):
self.__attr = 1
self._attr = 2
self.attr = 3
a = A()
print(a.__attr) # 报错
print(a._attr) # 2
print(a.attr) # 3
# Python当中私有的实现, 实际上就是变量名改了一个名字, 仅此而已

我们能够看到保护属性和公有属性在存储的时候都是原来的名字, 但是对于私有属性__attr在存储的时候名字变了, 在私有属性名字前使用了单下划线+类名作为前缀.
所以说如果我们在类中使用修改后的私有变量名, 是可以正常访问到私有变量的, 没错是这样的:
python
class A:
def __init__(self):
self.__attr = 1
self._attr = 2
self.attr = 3
a = A()
print(a._A__attr) # 1
print(a._attr) # 2
print(a.attr) # 3
所以之前在类外设置私有属性的值, 其实访问的不是类内的私有属性, 而是类外自己设置的一个新的属性, 因为类内的私有属性名字已经变了.
2. 继承
继承是面向对象编程中的一种重要特性, 它允许一个类(子类)从另一个类(父类)继承属性和方法, 并且可以在此基础上进行扩展和修改.
通过继承, 子类可以复用父类的代码, 避免重复编写相同的功能, 同时可以在子类中添加新的属性和方法, 或者重写父类的方法, 从而实现代码的灵活和易于扩展.
优势
- 代码重用: 继承允许子类从父类继承属性和方法, 避免了重复编写相同的代码, 提高了代码的重用性.
- 代码组织和扩展: 继承可以使代码的组织结构更加清晰, 将通用的功能封装在父类中, 特定的功能在子类中实现, 便于代码的维护和扩展.
- 代码复杂性降低: 继承使得代码的层次结构更加清晰, 提高了代码的可读性和可维护性, 降低了代码的复杂性.
语法
在Python中, 继承使用class 子类名(父类名)
的语法来实现, 子类拥有父类的所有属性和方法.子类可以直接使用父类的方法, 也可以在子类中添加新的方法或者重写父类的方法.(私有属性是不能继承过来的)
python
class Person:
# 类属性
id_number = 123123
def __init__(self, name):
self.name = name
def greet(self):
print(f"你好, 我叫 {self.name}")
class Student(Person):
"""单继承"""
def __init__(self, name, stu_id):
super().__init__(name)
self.name = name
self.stu_id = stu_id
def show_stu_id(self):
print(f"姓名: {self.name}, 学号: {self.stu_id}")
stu = Student('张三', 123)
stu.show_stu_id()
stu.greet()
print(stu.id_number)
# 姓名: 张三, 学号: 123
# 你好, 我叫 张三
# 123123
多继承
注意: Python虽然支持多继承, 但是不建议使用, 只使用单继承即可.
在Python中, 一个子类可以继承多个父类, 这种继承方式称为多继承.多继承允许子类同时拥有多个父类的属性和方法.
方法重写
子类可以重写父类的方法, 即在子类中重新实现与父类同名的方法.这样做可以根据子类的需要修改或扩展方法的行为.
调用父类的成员
super: super()
用于调用父类的成员, 它可以在子类中调用父类的成员.
python
class Singer:
def sing(self):
print("正在唱歌")
class Dancer:
def dance(self):
print("正在跳舞")
class SingerDancer(Singer, Dancer):
"""多继承"""
pass
singer_dancer = SingerDancer()
singer_dancer.sing()
singer_dancer.dance()
print(SingerDancer.mro())
# [<class '__main__.SingerDancer'>, <class '__main__.Singer'>, <class '__main__.Dancer'>, <class 'object'>]
# MRO 确保了在多继承的情况下,方法的调用顺序是明确且一致的. 它避免了方法调用的歧义,并确保了 Python 的多继承机制能够正确工作.
3. 多态
多态就是多种状态, 即做某一个行为(同样的行为)的时候, 使用不同的对象会得到不同的状态.
在面向对象编程中, 多态是一种重要的概念, 它允许不同的对象对相同的方法做出不同的响应.简而言之, 多态使得可以使用统一的接口来调用不同类的对象, 而无需关心对象的具体类型, 从而实现更灵活和可扩展的代码设计.
在Python中, 多态性是由动态类型和动态绑定实现的.具体来说, Python是一种动态类型语言, 这意味着变量的类型在运行时根据赋值而确定, 而不是在编译时确定.因此, 同一个方法名可以在不同的类中实现, 并且可以根据对象的类型调用不同类的方法
python
class Cat:
def say(self):
print("喵喵")
class Dog:
def say(self):
print("汪汪")
animal = Cat()
# animal = Dog()
animal.say()
4. 抽象基类
抽象基类(Abstract Base Classes, 简称ABC)是Python中的一个重要概念, 它允许我们定义抽象类和抽象方法, 从而可以规范子类的行为.
抽象基类并不能被实例化, 只能用于继承.子类必须实现抽象基类中定义的所有抽象方法.
Python中的抽象基类通过abc
模块提供, 使用抽象基类可以达到以下几个目的:
- 规范子类行为: 抽象基类允许我们定义一组接口或方法, 子类必须实现这些方法, 从而规范了子类的行为.
- 约束方法命名: 通过抽象基类可以强制子类必须实现指定的方法, 这样可以避免方法名拼写错误或者忘记实现方法的问题.
- 多态性支持: 抽象基类实现了多态性, 可以在使用抽象基类的地方接受多种不同的子类对象, 从而实现更灵活的代码设计.
- 文档化接口: 抽象基类可以帮助文档化接口, 让开发者了解哪些方法必须实现, 哪些是可选的.
python
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta): # ABCMeta 是一个元类,用于创建抽象基类
"""抽象基类"""
"""元类就是创建类的类"""
# abstractmethod 是一个装饰器,用于定义抽象方法
# 子类中必须实现这些抽象方法
@abstractmethod
def say(self):
# 在抽象基类中,当一个方法被定义为抽象方法时
# 通常会使用raise NotImplementedError来明确表示这个方法需要在子类中被具体实现
raise NotImplementedError
class Cat(Animal):
def say(self):
print("喵喵")
class Dog(Animal):
def say(self):
print("汪汪")
animal = Cat()
animal.say()
python
class Phone:# 抽象基类
def call(self): # 抽象方法
raise NotImplementedError
def music(self):
raise NotImplementedError
def wechat(self):
raise NotImplementedError
class Apple(Phone):
pass
class HuaWei(Phone):
pass
5. 补充练习
python
"""
设计一个图形类(Shape),包含计算面积的方法(calculate_area)。然后设计三个子类:圆类(Circle)、
矩形类(Rectangle)和三角形类(Triangle),分别实现计算面积的方法。要求实现以下功能:
分别创建圆、矩形和三角形的对象,并设置它们的相关属性(例如半径、长和宽、底和高等)。
分别调用这些对象的计算面积方法,并打印出计算结果。
"""
from math import pi
class Shape:
def calculate_area(self):
raise NotImplementedError
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def calculate_area(self):
area = pi * self.radius ** 2
return area
class Rectangle(Shape):
def __init__(self, length, width):
self.length = length
self.width = width
def calculate_area(self):
area = self.length * self.width
return area
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def calculate_area(self):
area = self.base * self.height * 0.5
return area
# shape = Circle(5)
# shape = Rectangle(5, 6)
shape = Triangle(5, 6)
_area = shape.calculate_area()
print(_area)
|----------------------|
| 遇见安然遇见你,不负代码不负卿。 |
| 谢谢老铁的时间,咱们下篇再见~ |