目录
第七章 面向对象
1 什么是面向对象
面向对象是一种抽象化的编程思想,是相对于面向过程而言的。面向对象将功能等通过对象来实现的,将功能封装进对象,让对象去实现其中具体的细节。一切皆为对象万物皆为对象。
【官方解释】:面向对象是软件开发方法,一种编程范式
举例来说,洗衣服的两种方法:
1、手洗:拿个桶,接水,将衣服泡湿,倒洗衣液,洗啊洗啊洗,倒掉一次两次三次水直到泡泡洗干净,拧干,晾衣服
2、机洗:扔衣服到洗衣机,倒洗衣液启动洗衣机,等待洗衣机洗好晾衣服
对比这两个,洗衣机洗衣服更加简单,洗衣服完成了手机需要的一二三四五N个步骤
思考:机洗,只需要找到一台洗衣机,加入简单操作就可以完成洗衣服的工作,而不需要关心洗衣机内部发生了什么事情。
面向过程强调的是过程,关注步骤、动作,我是执行者
面向对象就是将编程当成是一个事物,对外界来说,事物是直接使用的,不用去管他内部的情况。而编程就是设置事物能够做什么事。
Python是同时支持面向过程和面向对象的编程语言!
2、面向对象的三大特征:封装,继承、多态
1.封装:就是隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别【公有、私有】,将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体
好处:将变化隔离、便于使用、提高复用性、提高安全性
原则:将不需要对外提供的内容隐藏起来,把属性隐藏,提供公共方法对其访问
2.继承:子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和行为;或子类从父类继承方法,使得子类具有父类相同的行为。
提高代码复用性;继承是多态的前提
子类中所有的构造函数都会默认访问父类中的空参数的构造函数,默认第一行有super;若无空参数构造函数,子类中需指定;另外,子类构造函数中可自己用this指定自身的其他构造函数。
3.多态:是指不同类的对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式。 ==>官方解释
父类或接口定义的引用变量可以指向子类或具体实现类的实例对象
好处:提高了程序的扩展性
弊端:当父类引用指向子类对象时,虽提高了扩展性,但只能访问父类中具备的方法,不可访问子类中的方法:即访问的局限性。
前提:实现或继承关系;覆写父类方法。
2 概念
2.1 类!
类是抽象的概念,指的是对事物的某些描述信息, 通俗:类就是一个模板.
1:类是抽象的概念,对事物的某些描述信息; --[类就是一个模板, 老师给了大家一个表格:姓名、性别、毕业院校等]
2:(抽象)当你听到一个名词时,不能立马想到他的具体模样,这就是类.
定义在类中的函数,就叫做方法,方法后的第1个参数是self
方法的语法:跟函数类似,只不过多个参数self
定于类的语法如下:
class 类名:
def 方法名(self):
代码1
代码2
...
# 其他方法...
eg:定义汽车类
class Car:
def run(self):
print("汽车能跑起来...")
# 当定义了类后,执行没有直接的效果,需具体化后才有执行效果
几种定义类的方法:
class Teacher: #Python3用法
pass
class Student(): #可以兼容Python2
pass
class Phone(object): #建议使用
pass
2.2 对象!
对象是类的实例化,是具体的概念,是实实在在存在的个体,通俗:对象是通过模板创建出来的东西.
① 创建对象语法:对象名 = 类名() # 后面空括号
② 调用方法语法:对象名.方法名()
eg:调用上方定义的汽车类
# 1.创建对象,car为对象名
car=Car()
# 2.调用方法
car.run()
[变量名]命名对象名的规则:所有字母均小写,单词与单词之间使用下划线连接;
对象是具体的,看得见摸得着,有了对象及调用方法后,有执行结果
2.3 self关键字
self也是Python内置的关键字之一,其指向了对象实例本身【对象自己】。
注意:在类内部使用[self.属性名] 调用属性,使用self.[方法名]调用方法。
# 1.定义学生类,输出self
class Student:
def study(self):
print("=======================")
print("正在努力学习")
print("=================",self)
print("=======================")
# 睡觉类
def sleep(self):
# 调用当前对象的方法
self.study()
# 调用方法
stu=Student()
print(stu)
stu.study()
3 对象属性
什么是属性:
属性在面向对象中,可以使用变量来表示
属性可以在类内部、类外部都进行获取与使用
类外面访问属性,语法如下:
(1)添加属性:对象名.属性名 = 值
(2)获取属性:对象名.属性名
class Car():
def run(self):
print("汽车跑啊跑")
# 1.创建对象
car=Car()
# 2.添加属性
car.color="red"
car.number=4
# 3.获取属性
print(f"颜色:{car.color}")
print(f"轮胎数:{car.number}")
类内部访问属性:
语法:self.属性
class Car():
def run(self):
print("汽车跑啊跑")
# 定义方法
def show(self):
# 内部获取值
print(f"颜色:{self.color}")
print(f"轮胎数:{self.brand}")
# 1.创建对象
car=Car()
# 2.外部设定值
car.color="back"
car.brand="BMW"
# 3.获取属性
car.show()
4 魔法方法
魔法方法指的是:可以给Python类增加魔力的特殊方法。有两个特点:
(1)总是被双下划线所包围;
(2)在特殊时刻会被自动调用,不需要开发者手动去调用。
魔法方法语法:__魔法方法名__()
__init__(self [, ...])
:构造器,当一个对象被初始化创建时,会被自动调用。
__str__(self)
:输出对象名时,若不想直接输出内存地址值,可重写str()方法。
__del__(self)
:当一个对象被删除或销毁时,会被自动调用。
4.1 无参__init__() 方法!
在Python中,当新创建一个对象时,则会自动触发 __init__()
魔法方法。
__init__(self [, ...])
:构造器,当一个对象被初始化创建时,会被自动调用。
无参__init__()
方法语法:
class 类名:
def __init__(self):
代码
...
class Student:
def __init__(self):
print("执行了init...")
# 创建对象,创建对象时会自动调用 init 方法
stu=Student()
案例:
# 1.定义类:默认设置属性
class MyCar:
def __init__(self):
self.color="black"
self.number=3
def func(self):
print("===============")
print(f"颜色:{self.color}")
print(f"轮胎数:{self.number}")
print("===============")
# 2.在类的外部访问属性
my_car=MyCar()
print(my_car.color)
print(my_car.number)
# 3.类内部访问属性
my_car.func()
4.2 有参__init__() 方法!
当想要在创建对象时,就设定属性值时,可以使用有参 init() 初始化方法。创建对象时自动触发初始化方法。语法:
class 类名:
def __init__(self, 参数1, 参数2,...):
代码s
...
不需要给self传递参数值;传递参数个数的计算公式为【传递参数个数 = 定义方法后的参数总个数 - 1】
# 1.定义汽车类
class Car:
def __init__(self,color,number):
self.color=color
self.number=number
# 2.创建对象
car=Car("黑色",4)
# 3.获取值
print(f"颜色:{car.color}")
print(f"轮胎个数:{car.number}")
4.3__str__() 方法!
内存地址值,也称为引用。表现形式有两种:
(1)十进制数 5040624,id()函数
(2)十六进制数 0x45AC6
当直接输出对象名时,默认输出的是对象的内存地址值。
__str__(self)
:输出对象名时,若不想直接输出内存地址值,可重写str()方法。
语法:
class 类名:
def __str__(self):
代码
...
return 字符串型的结果
说明:必须返回字符串型的结果。
# 1.定义类
class Car:
def __init__(self,color,number):
self.color=color
self.number=number
def __str__(self):
return "颜色:"+self.color+",轮胎数:"+str(self.number)
# 2.创建对象
car=Car("黑色",4)
# 3.获取值
print(car)
int类型不能与字符串类型拼接,需要进行转换str(self.number)
return "颜色:"+self.color+",轮胎数:"+self.number TypeError: can only concatenate str (not "int") to str
4.4__del__() 方法
当删除对象时,会自动调用__del__()
方法。
__del__(self)
:当一个对象被删除或销毁时,会被自动调用。
class 类名:
def __del__(self):
代码
...
# 1.定义类
class Car:
def __init__(self,brand):
self.brand=brand
def __del__(self):
print("=========__del__===========")
return "颜色:"+self.brand
# 2.创建对象
car=Car("BYD")
# 3.获取值
# del car
print(car.brand)
运行结果如下:执行结束自动删除释放空间
BYD
=========__del__===========
5 继承基础
5.1 单继承
单继承就是一个子类继承一个父类。语法如下:
class 子类(父类):
...
# 1.定义父类
class Master(object):
def __init__(self):
self.pei_fang="[古老配方]"
def make_cake(self):
print("老师傅传授配方")
# 2.定义子类:徒弟单继承
class TuDi(Master):
pass
ff = TuDi()
print(f"属性:{ff.pei_fang}")
ff.make_cake()
5.1 多继承
多继承就是:一个类同时继承了多个父类。语法如下:
class 类名(父类1,父类2,...):
代码
...
# 1.定义父类
class Master(object):
def __init__(self):
self.pei_fang="[古老配方]"
def make_cake(self):
print("老师傅传授配方")
# 2.学校
class School(object):
def __init__(self):
self.pei_fang="[科技狠话新配方]"
def make_cake(self):
print("============采用新配方============")
# 3.定义子类:徒弟多继承
class TuDi(Master,School):
pass
多继承的顺序:
方式1:若要查看顺序问题,则可以使用"类名.mro"属性查看;
方式2:若要查看顺序问题,则可以使用"类名.mro()"方法查看.
# 1.定义父类
class Master(object):
def __init__(self):
self.pei_fang="[古老配方]"
def make_cake(self):
print("老师傅传授配方")
# 2.学校
class School(object):
def __init__(self):
self.pei_fang="[科技狠话新配方]"
def make_cake(self):
print("============采用新配方============")
def programming(self):
print("=========父类2 的方法")
# 3.定义子类:徒弟多继承
class TuDi(Master,School):
pass
# 创建对象,调用方法
ff = TuDi()
# 1.先去子类中查找该方法,存在调用
# 2.去第一个父类查找
# 3.去第二个父类查找
print(f"属性:{ff.pei_fang}")
ff.make_cake()
print(f"查看顺序问题:{TuDi.__mro__}")
print(f"查看顺序问题:{TuDi.mro()}")
运行结果如下:
属性:[古老配方]
父类1的方法:老师傅传授配方
查看顺序问题:(<class '__main__.TuDi'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>)
查看顺序问题:[<class '__main__.TuDi'>, <class '__main__.Master'>, <class '__main__.School'>, <class 'object'>]
1:子类要继承多个父类语法:
class 类名(父类1,父类2,...):
2:当子类调用多个父类的同名方法时,要查看顺序问题,可以使用"类名.mro"或"类名.mro()";
3:当某个父类新增了方法后,子类也能继承该方法;
4:当子类继承[多个]父类后,子类可以拥有[多个]父类的属性和方法.
5.3 继承进阶
① 子类重写父类同名方法和属性
方法重写
class Master(object):
def make_cake(self):
print("father")
# 方法重写
class TuDi(Master):
def make_cake(self):
print("sun")
# 创建对象
tudi=TuDi()
tudi.make_cake()
# 查看执行顺序
print(TuDi.mro())
调用父类同名方法
class School(object):
def __init__(self,pei_fang):
self.pei_fang=pei_fang
def make_cake(self):
print("father")
class TuDi(School):
def __init__(self,pei_fang,brand):
# self.pei_fang=pei_fang #提示代码的复用性
super().__init__(pei_fang)
self.brand=brand
def make_cake(self):
# 调用父类的方法
super().make_cake()
print("sun")
# 创建对象
tudi=TuDi("配方","品牌")
tudi.make_cake()
5.4 多层继承
多层继承表示有多层父类
# A父类 学校
class School(object):
def make_cake(self):
print("fantherA")
# B父类 徒弟
class TuDi(School):
def make_cake(self):
print("fantherB")
# B子类 徒孙
class TuSun(TuDi):
pass
6 面向对象综合案例
案例1:减肥
# 1.定义类
class Student(object):
def __init__(self,weight):
self.weight=weight
def run(self,i):
for j in range(0,i):
self.weight-=0.5
print(f"跑一次减一斤,跑了{i}圈,现在{self.weight}kg")
def eat(self):
self.weight+=2
print(f"大吃大喝一次胖4斤,现在{self.weight}kg")
def __del__(self):
print("=========__del__===========")
return "颜色:"+str(self.weight)
# 2.创建对象
xiaofang=Student(100)
# 3.调用方法
xiaofang.run(5)
xiaofang.eat()
案例1:烤地瓜
# 1.定义类
class Roast(object):
def __init__(self):
self.time_count = 0
self.raw = "生的"
self.seasoner_list=[]
# 烧烤
def bake(self, time):
self.time_count += time
# print(f"总共烤了{self.time_count}分钟")
if self.time_count<15:
self.raw="还没熟"
# print("还没熟")
elif 15 <= self.time_count <= 25:
# print("烤熟了")
self.raw = "熟了"
else:
self.raw="烤焦了"
# print("烤焦了")
# 添加调味料
def add(self,seasoner):
self.seasoner_list.append(seasoner)
# 输出对象名-信息
def __str__(self):
# print(len(self.seasoner_list))
if len(self.seasoner_list)==0:
print("暂无任何调料~",end="")
else:
print("添加的调味料有:",end="")
for temp in self.seasoner_list:
print(temp,end=" ")
print()
message=f"当前已经烤了{str(self.time_count)}分钟,目前地瓜的生熟状态是{self.raw}"
return message
# 创建对象
potato = Roast()
# 调用方法,烤10分钟,加调味料
potato.bake(10)
# potato.add("食用油")
print(potato)
# 调用方法,烤20分钟,加调味料
potato.bake(20)
potato.add("孜然粉")
potato.add("食用油")
potato.add("辣椒粉")
print(potato)
7 私有权限
私有属性仅能在本类中访问,不能直接被外部访问
设置私有权限的方式:在方法名前面加上两个下划线 __,格式:def __方法名(self):
# 1.父类
class Master(object):
def __init__(self):
self.__money=6000000
# 2.子类
class TuDi(Master):
pass
ff=TuDi()
print(ff.__money)
私有属性不能被外部访问
私有属性的获取
class Master(object):
def __init__(self):
self.__money=6000000
# 设置
def set_money(self,money):
self.__money=money
# 获取
def get_money(self):
return self.__money
# 创建对象
master=Master()
master.set_money(50000)
print(master.get_money())
8 私有方法
私有方法设定为私有权限后,不会被继承给子类
class Master(object):
def __make_secret(self):
print("==========================")
print("私有方法")
print("==========================")
# 简介访问
def use(self):
self.__make_secret()
# 创建类
master=Master()
# 调用私用方法
master.use()
9 对象属性和类属性
对象属性
class Phone(object):
def __init__(self,color,brand):
self.color=color
self.brand=brand
def show(self):
print(f"访问的车的颜色{self.color}")
phone=Phone("黑色","Audi")
print(f"颜色:{phone.color}")
print(f"品牌:{phone.brand}")
类属性
# 定义类
class People(object):
count=100
def show(self):
print("森林防火,人人有责")
# 调用使用
print(People.count)
10 类方法和静态方法
类方法
语法:
@classmethod #装饰器
def 类方法名(cls):
...
调用:
类名.类方法名() # 推荐使用
或对象名.类方法名()
class Dog(object):
# a类方法
@classmethod
def eat(cls):
print("类方法")
# 调用
Dog.eat()
dog=Dog()
dog.eat()
class Cat(object):
__tooch=10
# a类方法
@classmethod
def get_tooch(cls):
# return Dog.__tooch
return cls.__tooch
# 调用
print(Dog.get_tooch())
静态方法
静态方法需要通过装饰器@staticmethod来来标识其为静态方法,且静态方法不需要多定义参数,格式
如下:
@staticmethod
def 静态方法名():
...
调用:类名.静态方法名 # 推荐使用
对象名.静态方法
class Game(object):
# 定义静态方法,括号无参数
@staticmethod
def show_menu():
print("==================")
print("\t1.开始游戏")
print("\t2.暂停游戏")
print("\t3.结束游戏")
print("==================")
# 调用使用
Game.show_menu()
第八章 网络编程
三要素:IP地址、端口、协议。
IP地址:就是标识网络中设备的一个地址
端口:作用是找到计算机中的应用软件.
知名端口号:是指众所周知的端口号,范围从0到1023。 http:80 https:443 75
动态端口号:一般程序员开发应用程序使用端口号称为动态端口号, 范围是从1024到65535。
协议:作用是定义通信规则,并确定传输数据类型为bytes。
TCP协议:(Transmission Control Protocol)简称传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP的特点:
①面向连接:通信双方必须先建立好连接才能进行数据传输,数据传输完成后,需要断开连接,以释放系统资源。
②可靠传输:都建立了连接,传输数据可靠、稳定;
必须要先建立连接,相对效率较低;
大多数服务器程序都是使用TCP协议开发的。
1 socket套接字与TCP开发流程
只要跟网络相关的应用程序或者软件都使用到了socket 。
Python中有专门的socket类用来处理用户的请求和响应,利用socket类可以轻松实现两台计算机间的通信。
# 1.导入模块
import socket
# 2.创建socket对象
tcp_sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #TCP协议
# 3.输出内容
print(tcp_sock)
常用于服务器端的函数如下:
bind(address):绑定地址(host,port)到socket套接字,在AF_INET下,address以元组(host,port)的形式表示地址。其中,参数host表示字符串类型的主机名或IP地址;port表示int类型的端口号【1024-65535】。
listen(backlog):开始TCP监听。参数backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了,最大值可设置为128。
accept():被动接受TCP客户端连接,等待连接的到来,返回一个connection对象,以元组形式显示,且元组的第一个参数为已建立连接的socket对象,第二个参数为客户端地址address。
能同时应用于服务器端和客户端的函数如下:
recv(bufsize):用于接收TCP数据,数据以bytes二进制形式返回,bufsize指定要接收的最大数据量,可设置为1024的倍数。 4096=4*1024
send(data):发送TCP数据,将data中的数据发送到连接的套接字,data为bytes二进制数据。 bytes类型转换字符串。
close():关闭套接字。
setsockopt(level,optname,value):可设置端口号复用,让程序退出端口号并立即释放。level可指定为SOL_SOCKET, optname可指定为SO_REUSEADDR, value可指定为True。 了解
2 字符串str与二进制bytes类型转换
encode(encoding):用于把字符串编码转换为二进制数据,其中,encoding表示编码格式,常设置为 utf-8 。
decode(encoding):用于把二进制数据解码转换为字符串,其中,encoding表示编码格式,常设置为 utf-8 。
# ----------------------------12 字符串转换为二进制-----------------------
str="转换二进制"
# 转换二进制
result=str.encode("utf-8")
print(result)
# ----------------------------13 二进制转换为字符串-----------------------
# 二进制
bs=b"python"
# print(type(bs))
# 2.转换为字符串
result1=bs.decode("utf-8")
print(result1)
3 TCP编程
TCP服务器端操作步骤流程:
- 创建服务端套接字对象;socket()
- 绑定端口号;bind()
- 设置监听;listen()
- 等待接受客户端的连接请求;【被动连接】accept()
- 发送数据;send()
- 接收数据;recv()
- 关闭套接字。close()
服务器端server:创建一个socket对象服务器端,并向客户端发送消息内容
# 1.导入模块
import socket
# 2.创建socket对象
server_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #常量,大写,单词之间用下划线
# 3.绑定地址
host="127.0.0.1"
port=8000
address=(host,port)
server_socket.bind(address)
# 4.设置监听
server_socket.listen(5)
print(f"服务器正在端口号为{port}进行监听...")
# 5.被动连接[元组结果(被动socket,客户端地址)]
acc_sock,client_addr=server_socket.accept()
print(f"已成功连接,客户端地址为:{client_addr}")
# 6.发送消息
message="hello,Socket".encode("utf-8")
acc_sock.send()
server_socket.close()
print("===================服务客户端已结束")
TCP客户端操作步骤流程:
- 创建客户端套接字对象;socket()
- 客户端连接服务器端;connect()
- 接收数据;recv()
- 发送数据;send()
- 关闭套接字。close()
客户端:用来接收服务器端发送过来的内容。 receiver recv()
# 1.导入模块
import socket
# 2.创建socket对象
client_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 3.连接服务器
host="127.0.0.1"
port=8000
address=(host,port)
client_socket.connect(address)
# 4.接收消息
data=client_socket.recv(1024)
msg=data.decode("utf-8")
# 5.关闭
client_socket.close()
print("=======已经成功接受消息内容!!!")