第二章 强化
一、对象
1. 类的定义和使用
① 语法:
-
class 是关键字,表示要定义类了
-
类的属性,即定义在类中的变量(成员变量)
-
类的行为,即定义在类中的函数(成员方法)
# 创建类的语法 class 类名称: # 类的属性 xxx = xxx # 类的行为 def 方法名(self, 形参1, ......, 形参N): 方法体 # 创建类对象的语法 对象 = 类名称()
可以看到,在方法定义的参数列表中,有一个:self 关键字,self 关键字是成员方法定义的时候,必须填写的。
-
它用来表示类对象自身的意思
-
当我们使用类对象调用方法的是,self 会自动被 python 传入
-
在方法内部,想要访问类的成员变量,必须使用 self,如
self.name
注意:self 关键字,尽管在参数列表中,但是传参的时候可以忽略它。
2. 构造方法
① __init__
方法,称之为构造方法,该方法可以实现:
-
在创建类对象(构造类)的时候,会自动执行。
-
在创建类对象(构造类)的时候,将传入参数自动传递给
__init__
方法使用。
class student: name = None age = None tel = None # 定义该方法后,以上定义类属性的语句都可以省略 def __init__(self, name, age, tel): self.name = name self.age = age self.tel = tel stu = student("周杰轮", 31, "18500006666")
② ___str__
字符串方法
class student: def __init__(self, name, age): self.name = name self.age = age student = student("周杰轮", 11) print(student) # 结果: <__main__.student object at ox000002200CFD7040> print(str(student)) # 结果: <__main__.student object at 0x000002200CFD7040>
如上代码所示,当类对象需要被转换为字符串之时,会输出内存地址,内存地址没有多大作用,我们可以通过__str__()
方法,控制类转换为字符串的行为。
class student: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f"student类对象,name={self.name},age={self.age}" student = student("周杰轮", 11) print(student) # 结果: student类对象,name=周杰轮,age=11 print(str(student)) # 结果: student类对象,name=周杰轮,age=11
③ __lt__
小于符号比较方法
class student: def __init__(self,name,age): self.name = name self.age = age stu1 = student("周杰轮", 11) stu2 = student("林军杰", 13) print(stu1 < stu2) """ 结果: Traceback (most recent call last): File "D:\python-learn\test.py", line 11, in <module> print(stu1 < stu2) TypeError: '<' not supported between instances of 'Student' and 'Student' """
直接对 2 个对象进行比较是不可以的,但是在类中实现__lt__
方法,即可同时完成:小于符号和大于符号 2 种比较。
class Student: def __init__(self, name, age): self.name = name self.age = age def __lt__(self, other): return self.age < other.age stu1 = student("周杰轮", 11) stu2 = student("林军杰", 13) print(stu1 < stu2) # 结果: True print(stu1 > stu2) # 结果: False
④ __le__
小于等于比较符号方法
可用于:<=、>= 两种比较运算符上。
class student: def __init__(self, name, age): self.name = name self.age = age def __le__(self,other): return self.age <= other.age stu1 = student("周杰轮",11) stu2 = student("林军杰",13) print(stu1 <= stu2) # 结果: True print(stu1 >= stu2) # 结果: False
⑤ __eq__
比较运算符实现方法
-
不实现
__eq__
方法,对象之间可以比较,但是是比较内存地址,也即是:不同对象比较,一定是 False 结果。 -
实现了
__eq__
方法,就可以按照自己的想法来决定 2 个对象是否相等了。
class student: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): return self.age == other.age stu1 = student("周杰轮", 11) stu2 = student("林军杰", 11) print(stu1 == stu2) # 结果: True
3. 面向对象三大特性
封装、继承、多态。
4. 封装
① 将现实世界事物在类中描述为属性和方法,即为封装。
② 私有成员,定义私有成员的方式非常简单,只需要:
-
私有成员变量:变量名以
__
开头(2个下划线) -
私有成员方法:方法名以
__
开头(2个下划线)
即可完成私有成员的设置。
class Phone: IMEI = None # 序列号 producer = None # 厂商 __current_voltage = None # 当前电压,私有成员变量 def call_by_5g(self): print("5g通话已开启") def __keep_single_core(self): # 私有成员方法 print("让CPU以单核模式运行以节省电量")
注意:
-
类对象无法访问私有成员
-
类中的其它成员可以访问私有成员
5. 继承一
① 继承将从父类那里继承(复制)成员变量和成员方法到子类(不含私有)
② 单继承
语法:
class 类名(父类名): 类内容体
③ 多继承
语法:
class 类名(父类1, 父类2, ......, 父类N): 类内容体
注意:多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。即:先继承的保留,后继承的被覆盖。
③ pass 关键字
pass 是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思,可用于构造抽象方法。
class Phone: def call_by_5g(self): pass
6. 继承二
① 复写
子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写,即在子类中重新定义同名的属性或方法即可。
class Phone: IMEI = None # 序列号 producer = "Guizi" # 厂商 def call_by_5g(self): print("5g通话已开启") class MyPhone(Phone): producer = "SamoPig" # 复写父类属性 def call_by_5g(self): # 复写父类方法 print("子类的 5g 通话")
② 调用父类同名成员
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员;如果类定义中需要使用被复写的父类的成员,需要特殊的调用方式:
Ⅰ. 调用父类成员
-
使用成员变量:父类名.成员变量
-
使用成员方法:父类名.成员方法(self)
Ⅱ. 使用 super() 调用父类成员
-
使用成员变量:super().成员变量
-
使用成员方法:super().成员方法()
class Phone: IMEI = None # 序列号 producer = "ITCAST" # 厂商 def call_by_5g(self): print("父类的5g通话") c1ass MyPhone(Phone): producer = "ITHEIMA"" def call_by_5g(self): # 方式1调用父类成员 print(f"父类的品牌是:{Phone.producer}") Phone.call_by_5g(self) # 方式2调用父类成员 print(f"父类的品牌是:{super().producer}") super().call_by_5g() print("子类的5g通话")
注意:只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认是调用子类复写的。
7. 多态
① 多态指的是同样的行为(函数),传入不同的对象,得到不同的状态。如,定义函数(方法),通过类型注解声明需要父类对象,实际传入子类对象进行工作,从而获得不同的工作状态。
-
抽象类:含有抽象方法的类称之为抽象类。
-
抽象方法:方法体是空实现的(pass)称之为抽象方法。
② 多态中通常父类的方法是空实现,这种设计的含义是
-
父类用来确定有哪些方法
-
具体的方法实现,由子类自行决定。
c1ass 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.speak() dog = Dog() cat = Cat() make_noise(dog) # 输出: 汪汪汪 make_noise(cat) # 输出: 喵喵瞄
③ 作用:
-
多用于做顶层设计(设计标准),以便子类做具体实现。
-
也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法,并配合多态使用,获得不同的工作状态。
8. 变量类型注解
在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。主要功能:
-
帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示。
-
帮助开发者自身对变量进行类型注释。
① 语法一:变量名: 类型
Ⅰ. 基础数据类型注解
var_1: int = 10 var_2: float = 3.1415926 var_3: bool = True var_4: str = "itheima"
Ⅱ. 类对象类型注解
class student: pass stu: student = student()
Ⅲ. 基础容器类型注解
my_list: list = [1,2,3] my_tuple: tuple = (1,2,3) my_set: set = {1,2,3} my_dict: dict = {"itheima": 666} my_str: str = "itheima"
Ⅳ. 容器类型详细注解
my_list: list[int] =[1, 2, 3] my_tuple: tuple[str, int, bool] = ("itheima", 66, True) # 注意 my_set: set[int] = {1, 2, 3} my_dict: dict[str, int] = {"itheima": 666} # 注意
注意:
-
元组类型设置类型详细注解,需要将每一个元素都标记出来。
-
字典类型设置类型详细注解,需要 2 个类型,第一个是 key,第二个是 value。
② 语法二:# type: 类型
注意:
-
设置注解的情况一般是无法直接看出变量类型时,添加变量的类型注解。
-
类型注解只是提示性的,并非决定性的,即数据类型和注解类型无法对应也不会导致错误.
9. 函数(方法)类型注解
① 形参类型注解:
def 函数方法名(形参名: 类型, 形参名: 类型, ......): pass
② 返回值类型注解:
def 函数方法名(形参: 类型, ......, 形参: 类型) -> 返回值类型: pass
示例:
def func(x: int, y: int) -> int: pass
10. Union 类型
使用 Union 可以定义联合类型注解,可以表示联合类型注解中的任意一个。
# 导包 from typing import Union # Union[类型, ......, 类型] def func(data: Union[int, str]) -> Union[int, str]: pass
二、数据库
1. 安装第三方库
语法:pip install pymysql
2. 执行 SQL 语句
from pymysql import Connection # 一、获取到 MySQL 数据库的链接对象 conn = Connection( host='localhost', # 主机名(或 IP 地址) port=3306, # 端口,默认 3306 user='root', # 账户名 password='123456' # 密码 ) # 二、获取游标对象 cursor = conn.cursor() conn.select_db("test") # 选择数据库 # 三、使用游标对象,执行sql语句 cursor.execute("SELECT * FROM student") # 获取查询结果,得到的数据结构为 ((xx, xx, xx), ... , (xx, xx, xx)) results: tuple = cursor.fetchall() for r in results: print(r) # 四、关闭到数据库的链接 conn.close()
3. commit 提交
① pymysql 库在执行对数据库有修改操作的行为时,是需要通过链接对象的 commit 成员方法来进行确认的,只有确认的修改,才能生效中。
from pymysql import Connection conn = Connection( host='localhost', # 主机名(或 IP 地址) port=3306, # 端口,默认 3306 user='root', # 账户名 password='123456' # 密码 ) cursor = conn.cursor() conn.select_db("test") # 选择数据库 cursor.execute("insert into student values(10001,'周杰轮',31,'男')") # 通过 commit 确认 conn.commit() conn.close()
② 创建数据库连接时,设置自动提交:autocommit=True
conn = Connection( host="localhost", port=3306, user="root", password="123456", autocommit=True # 自动提交 )