类定义和使用
# 类定义
class Student:# 类属性name = Noneage = None# 类行为def test(self):print(f'我是{self.name},今年{self.age}岁。')# 类调用
stu = Student()
stu.name = 'Aiw'
stu.age = '20'
print(stu)
stu.test()
self
关键字是成员方法定义的时候,必须填写的:
- 它用来表示类对象自身的意思
- 当使用类对象调用方法的时候,self会自动被python传入
- 在方法内部,想要访问类的成员变量,必须使用self
self关键字,尽管在参数列表,但是传参的时候可以忽略它。
# 类定义 class Student:# 类属性name = Noneage = None# 类行为def test2(self, msg):print(f'新的消息是{msg}')stu.test2('666')
构造方法
Python类可以使用:__init__()方法,称之为构造方法。可以实现:
- 在创建类对象(构造类)的时候,会自动执行。
- 在创建类对象(构造类)的时候。将传入参数自动传递给__init__()方法使用
class Student:name = Noneage = Nonedef __init__(self, name, age):self.name = nameself.age = agedef say_hi(self):print(f'我是{self.name},今年{self.age}岁。') stu = Student('Aiw', 20)
stu.say_hi() # 我是Aiw,今年20岁。
在构造方法内定义成员变量,需要使用self关键字,因为变量是定义在构造方法内部,若要成为成员变量,需要用self来表示。
使用构造方法时,类属性可以省略不写
class Student:def __init__(self, name, age):self.name = nameself.age = agedef say_hi(self):print(f'我是{self.name},今年{self.age}岁。') stu = Student('Aiw', 20) stu.say_hi() # 我是Aiw,今年20岁。
魔术方法
__init__()构造方法,是Python类内置的方法之一。这些内置的类方法,各自有各自特殊的功能,这些内置方法称为:魔术方法。
__str__():控制类转换为字符串的行为。
# 类魔术方法
class Student:def __init__(self, name, age):self.name = nameself.age = agedef __str__(self):return f"Student[name={self.name},age={self.age}]"stu = Student('Aiw', 20)
print(stu) # Student[name=Aiw,age=20]
若不使用__str__()魔术方法,则会输出对象的内存地址
__lt__():对象比较方法,在类中实现__lt__()方法,即可同时完成:< 和 >2种比较。
# 类魔术方法
class Student:def __init__(self, name, age):self.name = nameself.age = agedef __lt__(self, other): # other:另一个类对象return self.age < other.agestu1 = Student('Aiw', 20)
stu2 = Student('Tom', 21)
print(stu1 < stu2) # True
print(stu1 > stu2) # False
若不使用__lt__()魔术方法,直接比较对象的话则会报错
__le__():对象比较方法,在类中实现__le__()方法,即可同时完成:<= 和 >=2种比较。
# 类魔术方法
class Student:def __init__(self, name, age):self.name = nameself.age = agedef __le__(self, other): # other:另一个类对象return self.age <= other.agestu1 = Student('Aiw', 20)
stu2 = Student('Tom', 21)
print(stu1 <= stu2) # True
print(stu1 >= stu2) # False
__eq__():对象比较方法,在类中实现__le__()方法,即可同时完成:== 1种比较。
# 类魔术方法
class Student:def __init__(self, name, age):self.name = nameself.age = agedef __eq__(self, other): # other:另一个类对象return self.age == other.agestu1 = Student('Aiw', 20)
stu2 = Student('Tom', 20)
print(stu1 == stu2) # True
不实现__eq__()方法,对象之间也可以比较,但是是比较内存地址,不同对象使用==来比较一定是False
封装
类中提够了私有成员的形式来支持。
- 私有成员变量
- 私有成员方法
定义私有成员的方式非常简单,只需要:
- 私有成员变量:变量名以__开通(2个下划线)
- 私有成员方法:方法名以__开通(2个下划线)
# 私有成员
class Student:__card_no = Nonedef __test(self):print('私有方法,无法直接调用')stu = Student()
print(stu.__card_no) # 获取私有变量(报错,无法获取)
print(stu.__test()) # 使用私有方法(报错,无法使用)
私有成员无法被类对象使用,但是可以被类中其它成员使用
# 私有成员 class Student:__card_no = Falsedef __test(self):print('私有方法,无法直接调用')def call(self):if self.__card_no:print('正确')else:self.__test()stu = Student() stu.call() # 私有方法,无法直接调用
继承
单继承基础语法:
class 类名(父类名):类内容体
示例:
# 单继承
class Phone:IMEI = None # 序列号producer = 'HM' # 厂商def call_4g(self):print('4G通话')class Phone2023(Phone):face_id = '435003' # 面部识别IDdef call_5g(self):print('5G通话')phone = Phone2023()
print(phone.IMEI)
print(phone.face_id)
print(phone.call_4g())
print(phone.call_5g())
Python类之间支持多继承,多继承基础语法:
class 类名(父类名1, 父类名2, 父类名3, ..., 父类名N):类内容体
多继承注意事项:多个父类中,如果有同名的成员,那么默认以继承的顺序(从左到右)为优先级。
即:先继承的保留,后继承的被覆盖
复写:在子类中重新定义同名的属性或方法即可。
# 复写
class Phone:IMEI = None # 序列号def call_4g(self):print('父类的4G通话')class MyPhone(Phone):IMEI = 'test' # 复写父类属性def call_4g(self): # 复写父类方法print('子类的4G通话')phone = MyPhone()
print(phone.IMEI) # test
phone.call_4g() # 子类的4G通话
调用父类同名成员:一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员;如果需要使用被复写的父类的成员,需要特殊的调用方式:
- 调用父类成员:
- 使用成员变量:
父类名.成员变量
或super().成员变量
- 使用成员方法:
父类名.成员方法(self)
或super().成员方法()
- 使用成员变量:
# 调用父类方法
class Phone:IMEI = None # 序列号def call_4g(self):print('父类的4G通话')class MyPhone(Phone):IMEI = 'test' # 复写父类属性def call_4g(self): # 复写父类方法# 方式1调用父类成员print(f'父类的序列号是{Phone.IMEI}')# 方式2调用父类成员print(f'父类的序列号是{super().IMEI}')print('子类的4G通话')
类型注解
Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。
类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。
主要功能:
- 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示。
- 帮助开发者自身对变量进行类型注释
支持:
- 变量的类型注解
- 函数(方法)形参列表和返回值的类型注解
为变量设置类型注解
基础语法:变量: 类型 = 值
# 基础数据类型注解(一般无需注解)
var_1: int = 10
var_2: str = 'hello'
var_3: bool = True
var_4: float = 3.1415926# 类对象类型注解(一般无需注解)
class Student:passstu: Student = Student()# 基础容器类型注解
my_list: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_set: set = {1, 2, 3}
my_dict: dict = {"age": 20}# 基础容器详细类型注解
my_list: list[int] = [1, 2, 3]
my_tuple: tuple[str, bool, int] = ("Aiw", True, 666)
my_set: set[int] = {1, 2, 3}
my_dict: dict[str, int] = {"age": 20}
- 元组类型设置类型详细注解,需要将每一个元素都标记出来
- 字典类型设置类型详细注解,需要2个类型,第一个是key,第二个是value
- 一般无法直接看出变量类型之时会添加变量的注解
- 类型注解仅仅只是个备注,哪怕标记错了,也不影响程序的运行
为函数(方法)形参设置类型注解
基础语法:def 函数(方法)名(形参名: 类型, 形参名: 类型, ...)
# 函数(方法)形参类型注解
def add(x: int, y: int):return x + y
为函数(方法)返回值设置类型注解
基础语法:def 函数(方法)名(形参名: 类型, 形参名: 类型, ...) -> 返回值类型
# 函数(方法)形参类型注解
def add(x: int, y: int) -> int:return x + y
Union联合类型注解
# Union联合注解
from typing import Unionmy_list: list[Union[str, int]] = [1, 2, 'Aiw']
my_dict: dict[str, Union[str, int]] = {'name': '周杰伦', 'age': 33}def fn(data: Union[int, str, list]) -> Union[int, str, list]:pass
Union联合类型注解,在变量注解、函数(方法)形参和返回值注解中,均可使用
多态
多态常作用在继承关系上,比如:
- 函数(方法)形参声明接收父类对象
- 实际传入父类的子类对象进行工作
即:
- 以父类做定义声明
- 以子类做实际工作
- 用以获得同一行为,不同状态
# 多态
class Animal:def seek(self):passclass Dog(Animal):def seek(self):print('汪汪汪')class Cat(Animal):def seek(self):print('喵喵喵')# 行为函数
def make_noise(animal: Animal) -> None:animal.seek()dog = Dog()
cat = Cat()make_noise(dog) # 汪汪汪
make_noise(cat) # 喵喵喵
父类Animal的seek()方法,是空实现。这种设计的含义是:
- 父类用来确定有哪些方法
- 具体的方法实现,由子类自行决定
这种写法,就叫做抽象类(也可以称之为接口)