一、初始对象
- 在程序中是可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的
- 在程序中设计表格,称之为设计类(class)
class Student:
name: None
- 在程序中打印生产表格,称之为创建对象
stu1 = Student()
stu2 = Student()
- 在程序中填写表格,称之为对象属性赋值
stu1.name = "jack"
stu2.name = "tom"
二、类与对象
1、类的定义和使用
- 类的定义
class 【类】:
【类的属性】
【类的行为】
- | 说明 |
---|---|
class | 关键字,表示要定义类 |
类的属性 | 定义在类中的变量(成员变量) |
类的行为 | 定义在类中的函数(成员方法) |
- 创建类对象
【对象】 = 类()
- 成员方法的定义
def 【方法】(self, 【形参 1】, 【形参 2】...):
【方法体】
- 在方法定义的参数列表中,有一个 self 关键字,它是成员方法定义的时必须填写的,用来表示类对象自身的意思,当使用类对象调用方法的是,self 会自动被 Python 传入(即可以忽略),在方法内部,想要访问类的成员变量,必须使用 self
2、演示
- 演示代码 1
class Student:
name: None
def sayHi(self):
print(f"Hello,我是 {self.name}")
def sayMsg(self, msg):
print(f"Hello,{msg}")
stu = Student()
stu.name = "jack"
stu.sayHi()
stu.sayMsg("今天天气不错")
- 输出结果
Hello,我是 jack
Hello,今天天气不错
- 演示代码 2
class Clock:
id = None # 编号
price = None # 价格
def ring(self):
print(f"闹钟 {self.id} 响铃了")
clock1 = Clock()
clock1.id = "001"
clock1.price = 10
clock2 = Clock()
clock2.id = "002"
clock2.price = 20
clock1.ring()
clock2.ring()
- 输出结果
闹钟 001 响铃了
闹钟 002 响铃了
三、类的成员方法
1、构造方法
(1)基本介绍
- Python 类可以使用 __init__ 方法,它是构造方法
-
在创建类对象(构造类)的时候,构造方法会自动执行
-
在创建类对象(构造类)的时候,Python 将传入参数自动传递给 __init__ 方法使用
-
构造方法也是成员方法,不要忘记在参数列表中提供 self,变量定义在构造方法内部,如果要成为成员变量,需要用 self 来表示
(2)演示
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
print("Student 类创建了一个对象")
def showInfo(self):
print(f"{self.name}, {self.age}, {self.address}")
stu = Student("jack", 20, "地球")
stu.showInfo()
- 输出结果
Student 类创建了一个对象
jack, 20, 地球
2、其他内置方法
- __init__ 方法,是 Python 类内置的方法之一,这些内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为魔术方法
(1)__str__ 方法
- 当类对象需要被转换为字符串时,默认会输出内存地址
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
stu = Student("jack", 20, "地球")
print(stu)
print(str(stu))
- 输出结果
<__main__.Student object at 0x000001DFE0D00FD0>
<__main__.Student object at 0x000001DFE0D00FD0>
- 内存地址没有多大作用,可以通过 __str__ 方法,控制类转换为字符串的行为
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __str__(self):
return f"Student: name={self.name}, age={self.age}, address={self.address}"
stu = Student("jack", 20, "地球")
print(stu)
print(str(stu))
- 输出结果
Student: name=jack, age=20, address=地球
Student: name=jack, age=20, address=地球
(2)__lt__ 方法
- 直接对 2 个对象进行比较是非法的
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
stu1 = Student("jack", 20, "地球")
stu2 = Student("tom", 15, "地球")
print(stu1 < stu2)
print(stu1 > stu2)
- 输出结果
TypeError: '<' not supported between instances of 'Student' and 'Student'
- 在类中实现 __lt__ 方法,可同时完成小于和大于两种比较
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __lt__(self, other):
return self.age < other.age
stu1 = Student("jack", 20, "地球")
stu2 = Student("tom", 15, "地球")
print(stu1 < stu2)
print(stu1 > stu2)
- 输出结果
False
True
(3)__gt__ 方法
- 比较大于符号的是 __gt__ 方法,不过,实现了 __lt__ 方法,__gt__ 方法就没必要实现了
(4)__le__ 方法
- __le__ 方法可用于小于等于和大于等于两种比较上
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __le__(self, other):
return self.age <= other.age
stu1 = Student("jack", 20, "地球")
stu2 = Student("tom", 15, "地球")
print(stu1 <= stu2) # False
print(stu1 >= stu2) # True
(5)__ge__ 方法
- 比较大于等于符号的是 __ge__ 方法,不过,实现了 __le__ 方法,__ge__ 方法就没必要实现了
(6)__eq__ 方法
- 对象之间可以比较,但是默认是比较内存地址,也就是不同对象比较结果一定是 False
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
stu3 = Student("mary", 30, "地球")
stu4 = Student("smith", 30, "地球")
print(stu1 == stu2)
- 输出结果
False
- 实现 __eq__ 方法就可以按照自己的方式来决定两个对象是否相等
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
stu3 = Student("mary", 30, "地球")
stu4 = Student("smith", 30, "地球")
print(stu1 == stu2)
- 输出结果
True
四、封装
1、基本介绍
-
封装表示的是将现实世界事物的属性和行为封装到类中,描述为成员变量和成员方法,从而完成程序对现实世界事物的描述
-
现实世界中的事物,有属性和行为,但是不代表这些属性和行为都是开放给用户使用的,例如,苹果越狱、安卓 root,也是为了突破权限使用这些对用户隐藏的属性和行为
-
现实事物有不公开的属性和行为,作为现实事物在程序中映射的类也支持,类中提供了私有成员的形式来支持,它们分别是私有成员变量和私有成员方法
-
定义私有成员变量:变量名以两个下划线(__)开头
-
定义私有成员方法:方法名以两个下划线(__)开头
- 私有变量无法赋值,也无法获取值,私有方法无法直接被类对象使用
2、演示
class Phone:
IMEI = None # 序列号
producer = None # 厂商
__current_volt = None # 当前电压
def call_by_5g(self):
print("开启 5G 通信")
def __keep_single_core(self):
print("让 CPU 以单核模式运行以节省电量")
- 使用私有成员变量
phone = Phone()
phone.__keep_single_core()
- 输出结果
AttributeError: 'Phone' object has no attribute '__keep_single_core'
- 使用私有成员方法
phone = Phone()
print(phone.__current_volt)
- 输出结果
AttributeError: 'Phone' object has no attribute '__current_volt'
3、补充
(1)补充说明
-
私有成员无法被类对象使用,但是可以被其它的成员使用
-
可以对类对象的与私有成员属性同名的属性赋值,但这是相当于又定义了一个新的变量,类内部的私有成员变量值不变
(2)演示
class Phone:
IMEI = None # 序列号
producer = None # 厂商
__current_volt = 10 # 当前电压
def call_by_5g(self):
if self.__current_volt >= 1:
self.__keep_single_core()
print("开启 5G 通信")
else:
print("通信失败,电量不足")
def __keep_single_core(self):
print("让 CPU 以单核模式运行以节省电量")
def show_current_volt(self):
print(self.__current_volt)
phone = Phone()
phone.__current_volt = 100
print(phone.__current_volt)
phone.show_current_volt()
phone.call_by_5g()
- 输出结果
100
10
让 CPU 以单核模式运行以节省电量
开启 5G 通信
五、继承
1、基本介绍
- 继承就是从父类那里继承(复制)来成员变量和成员方法(不含私有成员),继承分为单继承和多继承
class 【类】(【父类】):
【类体】
class 【类】(【父类 1】, 【父类 2】):
【类体】
- 注:多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级,即先继承的保留,后继承的被丢弃
2、演示
class Phone:
IMEI = None # 序列号
producer = None # 厂商
def call_by_4g(self):
print("开启 4G 通信")
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 Phone2023(Phone, NFCReader, RemoteControl):
face_id = True # 面部识别
def call_by_5g(self):
print("开启 5G 通信")
phone2023 = Phone2023()
phone2023.call_by_4g()
phone2023.call_by_5g()
phone2023.read_card()
phone2023.write_card()
print(phone2023.producer)
- 输出结果
开启 4G 通信
开启 5G 通信
读取 NFC 卡
写入 NFC 卡
None
3、复写和使用父类成员
(1)基本介绍
-
子类继承父类的成员属性和成员方法后,可以进行复写,一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
-
如果需要使用被复写的父类的成员,需要特殊的调用方式
- 调用父类成员
【父类】.【成员变量】
【父类】.【成员方法】(self)
- 使用 super() 调用父类成员
super().【成员变量】
super().【成员方法】()
(2)演示
class Phone:
IMEI = None
producer = "MY_PHONE"
def call_by_5g(self):
print("开启父类的 5G 通信")
class Phone2023(Phone):
producer = "MY_PHONE_2023"
def call_by_5g(self):
print("开启子类的 5G 通信")
def run_by_father(self):
print(super().producer)
super().call_by_5g()
phone2023 = Phone2023()
print(phone2023.producer)
phone2023.call_by_5g()
phone2023.run_by_father()
- 输出结果
MY_PHONE_2023
开启子类的 5G 通信
MY_PHONE
开启父类的 5G 通信
六、类型注解
1、类型注解引入
-
Python 在 3.5 版本的时候引入了类型注解,以方便静态类型检查工具、IDE 等第三方工具
-
类型注解就是在代码中涉及数据交互的地方提供数据类型的注解(显式的说明)
-
类型注解的主要功能就是帮助第三方 IDE 工具对代码进行类型推断,协助做代码提示,帮助开发者自身对变量进行类型注释
-
类型注解支持变量的类型注解和函数形参列表和返回值的类型注解
2、变量的类型注解
(1)基本注解
【变量】: 【类型】
- 基础数据类型注解
var_1: int = 10
var_2: float = 3.1415926
var_3: bool = True
var_4: str = "Hello World"
- 类对象类型注解
class Student:
name = None
age = None
stu: Student = Student()
- 基础容器类型注解
my_list: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_set: set = {1, 2, 3}
my_dict: dict = {"a1": 123}
my_str: str = "Hello World"
- 容器类型详细注解
m_list: list[int] = [1, 2, 3]
m_tuple: tuple[str, int, bool] = ("Hello", 10, True)
m_set: set[int] = {1, 2, 3}
m_dict: dict[str, int] = {"a1", 100}
(2)注释中的注解
# type: 【类型】
class Student:
name = None
age = None
def func():
return Student()
a = random.randint(1, 10) # type: int
b = json.loads('{"a1": 100}') # type: dict[str, 100]
c = func() # type: Student
(3)补充
- 为变量设置注解,显示的变量定义,一般无需注解,因为就算不写注解,也明确的知晓变量的类型,例如
var_1: int = 10
var_2: float = 3.1415926
var_3: bool = True
var_4: str = "Hello World"
- 一般,无法直接看出变量类型时会添加变量的类型注解,例如
a = random.randint(1, 10) # type: int
b = json.loads('{"a1": 100}') # type: dict[str, 100]
- 类型注解并不会真正的对类型做验证和判断,也就是说,类型注解仅仅是提示性的,不是决定性的,例如,如下代码不会报错
n1: int = "abc"
n2: str = 200
2、函数的类型注解
- 函数的形参和返回值都可以添加类型注解
def 【函数】(【形参】: 【类型】, 【形参】: 【类型】) -> 【返回值类型】:
【函数体】
def add(x: int, y: int) -> int:
return x + y
def addAll(data: list[int]) -> int:
sum = 0;
for x in data:
sum += x
return sum
res1: int = add(1, 2)
res2: int = addAll([1, 2, 3, 4, 5])
3、联合类型注解
(1)问题引入
- 如下代码的类型注解可以很容易定义
my_list1: list[int] = [1, 2, 3]
my_dict1: dict[str, int] = {"id": 10, "age": 20}
- 如下的代码的类型注解却不好定义
my_list2 = [1, 2, "Hello World"]
my_dict2 = {"name": "jack", "age": 20}
(2)解决方案
Union[【类型】, 【类型】]
- 联合类型注解,在变量注解、函数的形参和返回值注解中,均可使用
my_list3: list[Union[str, int]] = [1, 2, "Hello World"]
my_dict3: dict[str, Union[str, int]] = {"name": "jack", "age": 20}
def fn(data: Union[str, int]) -> Union[str, int]:
if type(data) == int:
return data * 10
if type(data) == str:
return data + data
print(fn(1)) # 10
print(fn("Hello")) # HelloHello
七、多态
1、基本介绍
-
多态指的是多种状态,即完成某个行为时,使用不同的对象会得到不同的状态,例如,实现某个功能的函数,传入不同的对象,得到不同的状态
-
多态常作用在继承关系上,例如,函数形参声明接收父类对象,实际传入父类的子类对象进行工作,即,以父类做定义声明,以子类做实际工作,用以获得同一行为,不同状态
2、演示
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
print("小狗汪汪叫")
class Cat(Animal):
def speak(self):
print("小猫喵喵叫")
def make_speak(animal: Animal):
animal.speak()
animal = Animal()
dog = Dog()
cat = Cat()
make_speak(animal)
make_speak(dog)
make_speak(cat)
- 输出结果
小狗汪汪叫
小猫喵喵叫
3、抽象类
(1)基本介绍
- 上述父类 Animal 的 speak 方法,是空实现(pass),这种设计的含义是父类用来确定有哪些方法,但具体的方法实现由子类自行决定,这种写法称之为抽象类(接口)
-
抽象类:含有抽象方法的类称之为抽象类
-
抽象方法:方法体是空实现的(pass)方法称之为抽象方法
(2)演示
class Person:
def eat(self):
pass
def work(self):
pass
class Teacher(Person):
def eat(self):
print("老师去教室食堂用餐")
def work(self):
print("老师开始教书")
class Worker(Person):
def eat(self):
print("工人去工地食堂用餐")
def work(self):
print("工人开始劳作")
teacher = Teacher()
worker = Worker()
teacher.eat()
teacher.work()
worker.eat()
teacher.work()
- 输出结果
老师去教室食堂用餐
老师开始教书
工人去工地食堂用餐
老师开始教书
标签:__,10,name,Python,self,多态,print,age,def
From: https://blog.csdn.net/weixin_52173250/article/details/142914972