文章目录
- 一 类和对象的概念
- 二 类的认识
- 2.1 类的定义和使用语法
- 2.2 成员变量和成员方法
- 三 类和对象
- 3.1 类和对象的关系
- 3.2 构造方法
- 3.3 魔术方法概述(内置类方法)
- 3.4 内置方法详解
- 四 面向对象三大特性
- 4.1 封装
- 4.1.1 封装的理解
- 4.1.2 私有成员变量和方法
- 4.1.3 封装练习案例
- 4.2 继承
- 4.2.1 基础语法
- 4.2.2 pass关键字
- 4.2.3 多继承注意事项
- 4.2.4 复写
- 4.2.5 调用父类同名成员
- 4.3 类型注解
- 4.3.1 变量的类型注解
- 4.3.2 函数(方法)的类型注解
- 4.2.3 Optional和Union类型
- 4.2.4 自定义类型
- 4.2.5 补充:PEP 484中定义的语法规则
- 五 多态
- 5.1 多态概念
- 5.2 抽象类(接口)
- 六 进阶内容
- 使用对象组织数据
- 1. 创建自定义类
- 2. 数据结构的封装
- 3. 组合和关联
- 4. 继承和多态
一 类和对象的概念
- Python 是一种面向对象的编程语言,它将数据和方法封装到对象中,使得代码更加模块化和易于维护。这意味着几乎所有的数据都是对象,并且所有的操作都是通过调用对象的方法来完成的。
类和对象的基本概念:
-
类(Class):类是对象的模板或蓝图,它定义了对象应该有的属性和方法。在类中,可以定义初始化方法
__init__
和其他方法,以及属性。 -
对象(Object):对象是类的实例,它是根据类的定义创建的。每个对象都有自己的属性和方法,但是这些属性和方法都是根据类的定义来的。
# 1. 设计类 class Student: name=None; # 2. 创建对象 stu_1=Student() stu_2=Student() # 3. 对象属性赋值 stu_1.name="熊二" stu_2.name= "翠花"
二 类的认识
2.1 类的定义和使用语法
- 类(class)是一种用于创建对象(instances)的蓝图或模板。对象是类的实例,通过类可以定义对象的属性和方法。
- 使用
class
是关键字定义类- 类的属性,即定义在类中的变量(成员变量)
- 类的行为,即定义在类中的函数(成员方法)
- 类的定义语法
# 定义一个类 class 类名: 类的属性 类的方法
- 创建类对象的语法
对象名称=类名称()
2.2 成员变量和成员方法
- 类中定义的属性(变量)——成员变量
- 类中定义的行为(函数)——成员方法
# 定义一个带有成员方法的类 class Student: name = None # 成员变量 学生姓名 # 成员方法 def say_hi(self): print(f"大家好呀,我是{self.name},欢迎大家多多关照") # 成员方法 def say_hi2(self, msg): print(f"大家好,我是:{self.name},{msg}") stu = Student() stu.name = "周杰轮" stu.say_hi2("哎哟不错哟")
- 在类中定义成员方法和定义函数基本一致,但仍有细微区别:
def 方法名(self,形参1,...,形参n): 方法体
- 在方法定义的参数列表中,有一个:
self
关键字。self关键字是成员方法定义的时候,必须填写的,用来表示类对象自身的意思 - 当使用类对象调用方法的是,
self
会自动被python
传入在方法内部,想要访问类的成员变量,必须使用self
- self关键字,尽管在参数列表中,但是传参的时候可以忽略它。
stu = Student() stu.name = "周杰轮" stu.say_hi2("哎哟不错哟")
三 类和对象
3.1 类和对象的关系
-
显示世界的事务和类
-
现实世界的事物也有属性和行为,类也有属性和行为。使用程序中的类,可以完美的描述现实世界的事物
-
创建类对象的语法
对象名称=类名称()
-
类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作这种套路,称之为:面向对象编程
3.2 构造方法
- Python类可以使用:
__init__()
方法,称之为构造方法。- 在创建类对象(构造类)的时候,会自动执行。
- 在创建类对象(构造类)的时候,将传入参数自动传递给
__init__
方法使用。
- 在构造方法内定义成员变量,需要使用self关键字。原因:变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示。
- 演示
# 演示使用构造方法对成员变量进行赋值
# 构造方法的名称:__init__
class Student:
# 该部分可以省略
# ---------
name=None;
age=None;
tel=None;
# ---------
def __init__(self, name, age ,tel):
self.name = name
self.age = age
self.tel = tel
print("Student类创建了一个类对象")
stu = Student("周杰轮", 31, "18500006666")
3.3 魔术方法概述(内置类方法)
- 在Python的类中,有一些特殊的内置方法(也称为魔术方法或双下划线方法),它们允许自定义类的行为,使其能够与Python的内置功能(如运算符、迭代等)进行交互。
- 常见的Python类内置方法的列表:
方法名 | 描述 |
---|---|
__init__(self, ...) | 初始化方法,创建对象时自动调用。 |
__str__(self) | 返回对象的可打印字符串表示。 |
__repr__(self) | 返回对象的官方字符串表示,通常用于重新创建对象。 |
__len__(self) | 返回对象的长度。 |
__getitem__(self, key) | 当使用索引访问对象的元素时调用。 |
__setitem__(self, key, value) | 当使用索引赋值给对象的元素时调用。 |
__delitem__(self, key) | 当使用del obj[key] 删除对象的元素时调用。 |
__iter__(self) | 返回一个可迭代对象,使对象可以被用于for 循环。 |
__next__(self) | 在迭代对象时,每次调用next() 函数时调用。 |
__eq__(self, other) | 当使用== 运算符比较两个对象时调用。 |
__lt__(self, other) | 当使用< 运算符比较两个对象时调用。 |
__gt__(self, other) | 当使用> 运算符比较两个对象时调用。 |
__add__(self, other) | 当使用+ 运算符进行对象相加时调用。 |
__sub__(self, other) | 当使用- 运算符进行对象相减时调用。 |
__mul__(self, other) | 当使用* 运算符进行对象相乘时调用。 |
__divmod__(self, other) | 当使用divmod() 函数进行对象除法和取余运算时调用。 |
__enter__(self) | 用于定义对象在with 语句中的上下文管理行为。 |
__exit__(self, exc_type, exc_value, traceback) | 用于定义对象在with 语句中的上下文管理行为。 |
- 这些内置方法可以通过在类中实现相应的函数来自定义类的行为,使其与Python的内置功能进行交互。
3.4 内置方法详解
- 在Python中定义一个类时,可以通过实现特定的内置方法来自定义类的行为。
__init__(self, ...)
: 初始化方法,在创建对象时自动调用。用于初始化对象的属性。
示例:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 25)
print(person.name) # 输出: Alice
print(person.age) # 输出: 25
__str__(self)
: 返回对象的可打印字符串表示。
示例:
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
return f"Book: {self.title} by {self.author}"
book = Book("The Great Gatsby", "F. Scott Fitzgerald")
print(book) # 输出: Book: The Great Gatsby by F. Scott Fitzgerald
__repr__(self)
: 返回对象的官方字符串表示,通常用于重新创建对象。
示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x}, {self.y})"
point = Point(3, 5)
print(repr(point)) # 输出: Point(3, 5)
__len__(self)
: 返回对象的长度。
示例:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3, 4, 5])
print(len(my_list)) # 输出: 5
__getitem__(self, key)
: 当使用索引访问对象的元素时调用。
示例:
class MyList:
def __init__(self, items):
self.items = items
def __getitem__(self, index):
return self.items[index]
my_list = MyList([10, 20, 30])
print(my_list[1]) # 输出: 20
__setitem__(self, key, value)
: 当使用索引赋值给对象的元素时调用。
示例:
class MyList:
def __init__(self, items):
self.items = items
def __setitem__(self, index, value):
self.items[index] = value
my_list = MyList([1, 2, 3])
my_list[1] = 10
print(my_list.items) # 输出: [1, 10, 3]
__delitem__(self, key)
: 当使用del obj[key]
删除对象的元素时调用。
示例:
class MyList:
def __init__(self, items):
self.items = items
def __delitem__(self, index):
del self.items[index]
my_list = MyList([1, 2, 3])
del my_list[1]
print(my_list.items) # 输出: [1, 3]
__iter__(self)
: 返回一个可迭代对象,使对象可以被用于for
循环。
示例:
class MyRange:
def __init__(self, start, end):
self.start = start
self.end = end
def __iter__(self):
return self
def __next__(self):
if self.start >= self.end:
raise StopIteration
value = self.start
self.start += 1
return value
my_range = MyRange(1, 4)
for num in my_range:
print(num) # 输出: 1 2 3
__eq__(self, other)
: 当使用==
运算符比较两个对象时调用。
示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
point1 = Point(3, 5)
point2 = Point(3, 5)
print(point1 == point2) # 输出: True
__lt__(self, other)
: 当使用<
运算符比较两个对象时调用。
示例:
class Circle:
def __init__(self, radius):
self.radius = radius
def __lt__(self, other):
return self.radius < other.radius
circle1 = Circle(5)
circle2 = Circle(8)
print(circle1 < circle2) # 输出: True
__gt__(self, other)
: 当使用>
运算符比较两个对象时调用。
示例:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def __gt__(self, other):
return self.width * self.height > other.width * other.height
rectangle1 = Rectangle(4, 6)
rectangle2 = Rectangle(3, 8)
print(rectangle1 > rectangle2) # 输出: False
__add__(self, other)
: 当使用+
运算符进行对象相加时调用。
示例:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
new_x = self.x + other.x
new_y = self.y + other.y
return Vector(new_x, new_y)
vector1 = Vector(2, 3)
vector2 = Vector(4, 1)
result = vector1 + vector2
print(result.x, result.y) # 输出: 6 4
__sub__(self, other)
: 当使用-
运算符进行对象相减时调用。
示例:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __sub__(self, other):
new_x = self.x - other.x
new_y = self.y - other.y
return Point(new_x, new_y)
point1 = Point(5, 8)
point2 = Point(3, 4)
result = point1 - point2
print
(result.x, result.y) # 输出: 2 4
__mul__(self, other)
: 当使用*
运算符进行对象相乘时调用。
示例:
class ComplexNumber:
def __init__(self, real, imag):
self.real = real
self.imag = imag
def __mul__(self, other):
new_real = self.real * other.real - self.imag * other.imag
new_imag = self.real * other.imag + self.imag * other.real
return ComplexNumber(new_real, new_imag)
complex1 = ComplexNumber(3, 2)
complex2 = ComplexNumber(1, 4)
result = complex1 * complex2
print(result.real, result.imag) # 输出: -5 14
__divmod__(self, other)
: 当使用divmod()
函数进行对象除法和取余运算时调用。
示例:
class CustomNumber:
def __init__(self, value):
self.value = value
def __divmod__(self, other):
quotient = self.value // other.value
remainder = self.value % other.value
return quotient, remainder
num1 = CustomNumber(20)
num2 = CustomNumber(3)
quotient, remainder = divmod(num1, num2)
print(quotient, remainder) # 输出: 6 2
__enter__(self)
和__exit__(self, exc_type, exc_value, traceback)
: 用于定义对象在with
语句中的上下文管理行为。
示例:
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
self.file.close()
with FileManager("example.txt", "r") as file:
content = file.read()
print(content)
# 文件在退出上下文后自动关闭
四 面向对象三大特性
- 面向对象编程,是许多编程语言都支持的一种编程思想。
- 简单理解:基于模板(类)去创建实体(对象),使用对象完成功能开发。
面向对象包含3大主要特性:
- 封装
- 继承
- 多态
4.1 封装
4.1.1 封装的理解
- 封装:将现实世界事物的属性和方法,封装到类中描述为成员变量、成员方法,从而完成程序对现实世界事物的描述。
- 封装会对用户隐藏属性和方法
- 类中提供了私有成员的形式来支持隐藏属性和方法:私有成员变量、私有成员方法
4.1.2 私有成员变量和方法
定义私有成员的方式非常简单,只需要:
- 私有成员变量:变量名以__开头(2个下划线)
- 私有成员方法:方法名以__开头(2个下划线)
# 定义一个类,内含私有成员变量和私有成员方法
class Phone:
# 私有成员变量
__current_voltage = 0.5 # 当前手机运行电压
# 私有成员方法
def __keep_single_core(self):
print("让CPU以单核模式运行")
def call_by_5g(self):
if self.__current_voltage >= 1:
print("5g通话已开启")
else:
self.__keep_single_core()
print("电量不足,无法使用5g通话,并已设置为单核运行进行省电。")
phone = Phone()
phone.call_by_5g()
- 私有方法无法直接被类对象使用
- 私有变量无法赋值,也无法获取值
- 私有成员无法被类对象使用,但是可以被其它的成员使用。
4.1.3 封装练习案例
设计一个手机类,内部包含:
- 私有成员变量:__is_5g_enable,类型bool,True表示开启5g,False表示关闭5g
- 私有成员方法:__check_5g(),会判断私有成员__is_5g_enable的值
- 若为True,打印输出:5g开启
- 若为False,打印输出:5g关闭,使用4g网络
- 公开成员方法:call_by_5g(),调用它会执行
- 调用私有成员方法:__check_5g(),判断5g网络状态
- 打印输出:正在通话中
运行结果:
# 设计一个类,用来描述手机
class Phone:
# 提供私有成员变量:__is_5g_enable
__is_5g_enable = False # 5g状态
# 提供私有成员方法:__check_5g()
def __check_5g(self):
if self.__is_5g_enable:
print("5g开启")
else:
print("5g关闭,使用4g网络")
# 提供公开成员方法:call_by_5g()
def call_by_5g(self):
self.__check_5g()
print("正在通话中")
phone = Phone()
phone.call_by_5g()
4.2 继承
4.2.1 基础语法
- 继承分为:单继承和多继承
- 继承表示:将从父类那里继承(复制)来成员变量和成员方法(不含私有)
# 单继承
class 类名(父类名)
类内容体
# 多继承
class 类名(父类1,父类2,...,父类N)
类内容体
# 演示单继承
class Phone:
IMEI = None # 序列号
producer = "ITCAST" # 厂商
def call_by_4g(self):
print("4g通话")
class Phone2022(Phone):
face_id = "10001" # 面部识别ID
def call_by_5g(self):
print("2022年新功能:5g通话")
phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
- Python的类之间也支持多继承,即一个类,可以继承多个父类
# 演示多继承
class NFCReader:
nfc_type = "第五代"
producer = "HM"
def read_card(self):
print("NFC读卡")
def write_card(self):
print("NFC写卡")
class RemoteControl:
rc_type = "红外遥控"
def control(self):
print("红外遥控开启了")
class MyPhone(Phone, NFCReader, RemoteControl):
pass
phone = MyPhone()
phone.call_by_4g()
phone.read_card()
phone.write_card()
phone.control()
print(phone.producer)
4.2.2 pass关键字
- pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思
pass
的主要用途包括:
-
占位符:当在开发过程中正在编写框架或者计划添加代码逻辑但还没有完成时,可以使用
pass
来避免语法错误。 -
空函数或类:定义一个函数或类,但是暂时没有需要放入其中的代码。这时可以使用
pass
来定义一个空函数或空类。
示例:
# 占位符示例
if some_condition:
pass # 以后填充条件的实际逻辑
# 定义空函数
def empty_function():
pass # 暂时没有函数体,之后可能添加逻辑
# 定义空类
class EmptyClass:
pass # 暂时没有类的成员,之后可能添加属性和方法
4.2.3 多继承注意事项
- 多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。即:先继承的保留,后继承的被覆盖
- 这个概念被称为"方法解析顺序"(Method Resolution Order,简称MRO)。Python使用C3线性化算法来计算MRO,以确定调用同名成员时的优先级。
class A:
def show(self):
print("A")
class B:
def show(self):
print("B")
class C(A, B):
pass
class D(B, A):
pass
obj1 = C()
obj2 = D()
obj1.show() # 输出: A,因为 A 在 C 的继承列表的左边
obj2.show() # 输出: B,因为 B 在 D 的继承列表的左边
4.2.4 复写
- 在面向对象编程中,子类可以通过复写(覆盖)父类的成员(方法或属性)来改变其行为。当子类定义了与父类同名的方法或属性时,子类的成员会覆盖父类的成员,从而在子类的实例中执行子类自己的逻辑。
示例:
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def speak(self):
print("Dog barks")
class Cat(Animal):
def speak(self):
print("Cat meows")
animal = Animal()
dog = Dog()
cat = Cat()
animal.speak() # 输出: Animal speaks
dog.speak() # 输出: Dog barks
cat.speak() # 输出: Cat meows
4.2.5 调用父类同名成员
- 一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员。如果需要使用被复写的父类的成员,需要特殊的调用方式:
方式1: - 调用父类成员
- 使用成员变量:父类名.成员变量
- 使用成员方法:父类名.成员方法(self)
方式2:
- 使用super()调用父类成员
- 使用成员变量:super().成员变量
- 使用成员方法:super().成员方法()
以下是一个调用父类方法的示例:
class Vehicle:
def start(self):
print("Vehicle started")
class Car(Vehicle):
def start(self):
super().start() # 调用父类方法
print("Car started")
car = Car()
car.start()
输出:
Vehicle started
Car started
-
只能在子类内调用父类的同名成员,子类的类对象直接调用会调用子类复写的成员
-
当子类复写了父类的成员(方法或属性),在子类内部可以通过
super()
函数来调用父类的同名成员。这是因为子类复写后,父类的成员被覆盖,但如果希望在子类中使用父类的实现,可以使用super()
来实现这一点。 -
然而,在子类的类对象直接调用成员时,会调用子类自己复写的成员。这是因为类对象直接访问成员时,不会触发
super()
的机制,而是直接使用类对象中的成员。
示例:
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def speak(self):
print("Dog barks")
class Cat(Animal):
def speak(self):
print("Cat meows")
dog = Dog()
cat = Cat()
dog.speak() # 输出: Dog barks
cat.speak() # 输出: Cat meows
# 类对象调用
Dog.speak() # 输出: Dog barks
Cat.speak() # 输出: Cat meows
- 通过实例(对象)调用
speak()
方法时,会根据对象的类型调用相应的方法。但是,当您通过类对象直接调用speak()
方法时,将会根据类对象的定义来调用方法,而不会触发super()
机制。这导致了子类自己复写的方法被调用。
4.3 类型注解
- Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。
- 类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。它不会影响程序的实际执行,但可以提供更好的代码可读性、静态分析和类型检查。
- 类型注解使用PEP 484中定义的语法规则
主要功能: - 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
- 帮助开发者自身对变量进行类型注释
支持:
- 变量的类型注解
- 函数(方法)形参列表和返回值的类型注解
4.3.1 变量的类型注解
基础语法:
变量: 类型
- 类型注解的一些常见用法:
- 变量注解:
x: int = 5 name: str = "Alice"
- 容器类型注解:
- 元组类型设置类型详细注解,需要将每一个元素都标记出来
- 字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
# 基础容器类型注解 my_list: list = [1, 2, 3] my_tuple: tuple = (1, 2, 3) my_dict: dict = {"itheima": 666} # 容器类型详细注解 my_list: list[int] = [1, 2, 3] my_tuple: tuple[int, str, bool] = (1, "itheima", True) my_dict: dict[str, int] = {"itheima": 666}
- 在注释中添加类型注解
# 在注释中进行类型注解 var_1 = random.randint(1, 10) # type: int var_2 = json.loads('{"name": "zhangsan"}') # type: dict[str, str] def func(): return 10 var_3 = func() # type: int
- 尽管这种方式在早期版本的Python中是一种常见的做法,但它并不是官方推荐的类型注解方式,因为它不会被类型检查工具如
mypy
等识别和解析。官方推荐的类型注解方式是使用PEP 484中定义的语法规则。
- 尽管这种方式在早期版本的Python中是一种常见的做法,但它并不是官方推荐的类型注解方式,因为它不会被类型检查工具如
- 官方推荐的类型注解方式
from typing import Dict var_1: int = random.randint(1, 10) var_2: Dict[str, str] = json.loads('{"name": "zhangsan"}') def func() -> int: return 10 var_3: int = func()
4.3.2 函数(方法)的类型注解
- 函数和方法的形参类型注解语法:
def 函数方法名(形参名:类型,形参名:类型) 内容体
- 函数(方法)的返回值类型注解的语法
def 函数方法名(形参名:类型,形参名:类型)->返回值类型
内容体
- 演示:
- 函数参数注解:
def greet(name: str) :
print f"Hello, {name}"
- 函数返回值注解:
def add(a: int, b: int) -> int:
return a + b
- 复杂数据类型注解:
from typing import List, Tuple
def process_data(data: List[Tuple[str, int]]) -> List[str]:
result = [f"{name}: {value}" for name, value in data]
return result
4.2.3 Optional和Union类型
- Optional 和 Union 是用于类型注解中表示可选值或多种可能类型的重要工具
- Optional用于表示一个值可以是特定类型,也可以是None。这在函数参数和返回值注解中特别有用,因为它允许参数可以是指定的类型,也可以是None。
- 使用
Union[类型, ......, 类型]
可以定义联合类型注解 - Union联合类型注解,在变量注解、函数(方法)形参和返回值注解中,均可使用。
- Optional类型:表示可选的类型。
- age参数可以是int类型,也可以是None
from typing import Optional
def print_age(age: Optional[int]) -> None:
if age is not None:
print(f"Age: {age}")
- Optional和Union类型:表示多种可能的类型。
from typing import Union
def combine(a: Union[int, float], b: Union[int, float]) -> Union[int, float]:
return a + b
4.2.4 自定义类型
NewType
是 Python 的typing
模块中的一个工具,用于创建新的、独特的类型别名。它用于为现有的基本数据类型创建更具有语义的新类型,以提高代码的可读性和类型检查。
在实际使用中,NewType
并不会引入新的数据结构或运行时类型检查,它只是为了在类型注解中提供更多的语义信息,以及帮助类型检查工具识别不同的类型别名。
-
以下是使用
NewType
来自定义新的类型别名的示例:from typing import NewType # 使用 NewType 创建 UserId 类型 UserId = NewType('UserId', int) def get_user_name(user_id: UserId) -> str: return f"User {user_id}"
- 在这个例子中,通过
NewType
创建了一个新的类型UserId
,它是一个整数 (int
) 的别名。尽管UserId
在类型注解中使用起来与int
类型一样,但它有助于代码的可读性和类型检查。类型检查工具会将UserId
视为不同于普通int
的类型,从而提高了代码的安全性和可维护性。
- 在这个例子中,通过
-
注意,
NewType
不会在运行时引入额外的开销,因为它只是在类型注解中添加了更多的信息。在类型检查工具中,它可以帮助捕获一些潜在的类型错误。
4.2.5 补充:PEP 484中定义的语法规则
PEP 484定义了Python中类型注解的语法规则。以下是一些重要的语法规则和概念:
-
基本类型注解:使用内置的基本数据类型来进行注解,如
int
、float
、str
等。x: int = 5 name: str = "Alice"
-
复杂数据类型注解:使用
typing
模块中的类型来注解复杂数据类型,如List
、Tuple
、Dict
等。from typing import List, Tuple def process_data(data: List[Tuple[str, int]]) -> List[str]: result = [f"{name}: {value}" for name, value in data] return result
-
函数参数和返回值注解:使用
->
箭头表示函数的返回值类型注解。def add(a: int, b: int) -> int: return a + b
-
Optional 和 Union 类型:使用
Optional
表示一个可选的类型,使用Union
表示多种可能的类型。from typing import Optional, Union def print_age(age: Optional[int]) -> None: if age is not None: print(f"Age: {age}") def combine(a: Union[int, float], b: Union[int, float]) -> Union[int, float]: return a + b
-
Type Aliases(类型别名):使用
TypeVar
来创建泛型类型参数,使用NewType
来创建自定义的类型别名。from typing import TypeVar, NewType T = TypeVar('T') def repeat_item(item: T, times: int) -> List[T]: return [item] * times UserId = NewType('UserId', int)
- PEP 484中定义的一些基本语法规则,允许你为变量、函数参数和返回值添加类型注解,从而提高代码的可读性和可维护性。
- 类型注解并不会影响程序的实际执行,但可以在编辑器、IDE和类型检查工具中提供更好的代码分析和错误检测。
五 多态
5.1 多态概念
- 多种状态,即完成某个行为时,使用不同的对象会得到不同的状态。
- 多态常作用在继承关系上。比如:函数(方法)形参声明接收父类对象,实际传入父类的子类对象进行工作。即:以父类做定义声明,以子类做实际工作,用以获得同一行为, 不同状态
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
def make_noise(animal: Animal):
"""制造点噪音,需要传入Animal对象"""
animal.speak()
# 演示多态,使用2个子类对象来调用函数
dog = Dog()
cat = Cat()
make_noise(dog) # "汪汪汪"
make_noise(cat) # "喵喵喵"
5.2 抽象类(接口)
- 父类Animal的speak方法,是空实现
这种设计的含义是:- 父类用来确定有哪些方法
- 具体的方法实现,由子类自行决定
- 这种写法,就叫做抽象类(也可以称之为接口)
抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现的(pass)称之为抽象方法
- 抽象类的抽象方法子类必须实现
# 演示抽象类
class AC:
def cool_wind(self):
"""制冷"""
pass
def hot_wind(self):
"""制热"""
pass
def swing_l_r(self):
"""左右摆风"""
pass
class Midea_AC(AC):
def cool_wind(self):
print("美的空调制冷")
def hot_wind(self):
print("美的空调制热")
def swing_l_r(self):
print("美的空调左右摆风")
class GREE_AC(AC):
def cool_wind(self):
print("格力空调制冷")
def hot_wind(self):
print("格力空调制热")
def swing_l_r(self):
print("格力空调左右摆风")
def make_cool(ac: AC):
ac.cool_wind()
midea_ac = Midea_AC()
gree_ac = GREE_AC()
make_cool(midea_ac)
make_cool(gree_ac)
六 进阶内容
使用对象组织数据
- 在Python中,使用对象来组织数据,以便更好地管理和操作复杂的信息。对象允许将相关数据和方法封装在一起,使得代码更加模块化、可维护和可扩展。
1. 创建自定义类
- 通过创建自定义类,定义一个新的数据类型,以适应应用程序的需求。这个类可以包含属性和方法,用于描述和操作该数据类型。
class Student:
def __init__(self, name, age, grade):
self.name = name
self.age = age
self.grade = grade
def get_info(self):
return f"Name: {self.name}, Age: {self.age}, Grade: {self.grade}"
# 创建学生对象
student1 = Student("Alice", 16, "10th")
student2 = Student("Bob", 17, "11th")
# 访问对象的属性和方法
print(student1.get_info()) # 输出: Name: Alice, Age: 16, Grade: 10th
print(student2.get_info()) # 输出: Name: Bob, Age: 17, Grade: 11th
2. 数据结构的封装
使用对象来封装复杂的数据结构,例如列表、字典或其他对象,以创建更有结构的数据模型。
class ShoppingCart:
def __init__(self):
self.items = []
def add_item(self, item):
self.items.append(item)
def calculate_total(self):
total = 0
for item in self.items:
total += item['price']
return total
# 创建购物车对象
cart = ShoppingCart()
# 添加商品
cart.add_item({'name': 'Apple', 'price': 1})
cart.add_item({'name': 'Banana', 'price': 0.5})
# 计算总价
total_price = cart.calculate_total()
print(f"Total Price: ${total_price}")
3. 组合和关联
- 将不同类型的对象组合起来,以表示更复杂的概念和关系。例如,一个学校对象可以包含多个学生对象。
class School:
def __init__(self, name):
self.name = name
self.students = []
def add_student(self, student):
self.students.append(student)
def get_student_names(self):
return [student.name for student in self.students]
# 创建学校对象
school = School("ABC School")
# 添加学生
school.add_student(student1)
school.add_student(student2)
# 获取学生姓名列表
student_names = school.get_student_names()
print(f"Student Names: {student_names}")
4. 继承和多态
- 通过继承和多态性,创建一个类层次结构,其中不同的类可以共享一些相似的属性和方法,并在需要时实现特定的行为。
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
# 创建动物对象
dog = Dog()
cat = Cat()
# 调用不同的 speak 方法
print(dog.speak()) # 输出: Woof!
print(cat.speak()) # 输出: Meow!