一、复习
1. 私有化: 命名的时候两个下划线开头
2. getter和setter
getter - 想要获取属性做的别的事情
setter - 想要给属性赋值的时候做别的事情
- 1) 属性名前加一个'_'
- 2) 添加getter
@property
def getter名(self):
做别的事情
return 值
- 3)添加setter
@getter名.setter
def setter名(self, 参数):
做别的事情
给属性赋值
3. 方法
1)对象方法
怎么声明: 直接声明在类的中函数
特点: 有默认参数self, 不需要传参,指向当前对象
怎么调用: 对象调用
什么时候: 实现函数的功能需要对象的属性2)类方法
怎么声明: 声明函数前加@classmethod
特点: 有默认参数cls, 不需要传参, 指向当前类
怎么调用: 类调用
什么时候:实现函数的功能不需要对象的属性的前提下需要类的字段3)静态
怎么声明: 声明函数前加@staticmethod
特点: 没有默认参数
怎么调用: 类调用
什么时候: 实现函数的功能既不需要对象属性也不需要类的字段
4. 继承 - 让子类直接拥有父类的属性和方法
python支持继承语法,默认的类都是继承object; 并且支持多继承
1)子类添加内容
字段和方法直接声明
添加对象属性2) 重写方法
注意: 多继承的时候可以继承多个类的方法和字段, 但是只能继承第一个类的对象属性
class Person:
def __init__(self, name, age=0):
self.name = name
self.age = age
self.gender = '女'
def show(self):
print('姓名: %s 年龄:%d' % (self.name, self.age))
class Student(Person):
def __init__(self, name1, score, age=0):
super().__init__(name1, age)
self.stu_id = '001'
self.score = score
def show(self):
print('姓名: %s 年龄:%d 分数:%d' % (self.name, self.age, self.score))
stu = Student('小明', 90, 20)
print(stu.__dict__)
stu.show()
p1 = Person('张三')
p1.show()
class Animal(object):
def __init__(self):
self.age = 0
self.weight = 10
@staticmethod
def eat(food):
print('动物吃%s' % food)
class Fly(object):
def __init__(self):
self.height = 100
self.speed = 80
def stop(self):
print('停止飞行')
print(self.speed)
print(self.height)
# self.speed = 0
# self.height = 0
class Bird(Animal, Fly):
pass
b1 = Bird()
Bird.eat('虫子')
b1.stop()
# print(b1.weight, b1.age)
# print(b1.height, b1.speed)
二、作业
1. 建立一个汽车类Auto,包括轮胎个数,汽车颜色,车身重量,速度等属性,并通过不同的构造方法创建实例。至少要求 汽车能够加速 减速 停车。
再定义一个小汽车类CarAuto 继承Auto 并添加空调、CD属性,
并且重新实现方法覆盖加速、减速的方法
class Auto:
def __init__(self, color='白色', weight=50, speed=0):
# color='红色', weight=100, speed=10
self.tyre_count = 4
self.color = color
self.weight = weight
self.speed = speed
self.__max_speed = 300
def speed_up(self, value):
"""加速"""
new_speed = self.speed + value
if new_speed > self.__max_speed:
self.speed = self.__max_speed
else:
self.speed = new_speed
def speed_down(self, value):
"""减速"""
new_speed = self.speed - value
if new_speed < 0:
self.speed = 0
else:
self.speed = new_speed
def stop(self):
"""停车"""
self.speed = 0
class CarAuto(Auto):
def __init__(self, color='', weight=100, speed=10):
# color='红色', weight=100, speed=10
super().__init__(color, weight, speed) # super().__init__('红色', 100, 10)
self.CD = ''
self.air_conditioner = '格力'
c1 = CarAuto('红色')
print(c1.__dict__)
3. 创建一个动物类,拥有属性:性别、年龄、颜色、类型 ,要求打印这个类的对象的时候以'/XXX的对象: 性别-? 年龄-? 颜色-? 类型-?/' 的形式来打印
class Animal:
def __init__(self, gender='公', age=1, color='黑色', type='爬行'):
self.gender = gender
self.age = age
self.color = color
self.type = type
def __repr__(self):
return '/%s的对象: 性别-%s 年龄-%d 颜色-%s 类型-%s/' % \
(self.__class__.__name__, self.gender, self.age, self.color, self.type)
class Dog(Animal):
pass
an1 = Animal()
print(an1)
dog1 = Dog()
print(dog1)
4. 写一个圆类, 拥有属性半径、面积和周长;要求获取面积和周长的时候的时候可以根据半径的值把对应的值取到。但是给面积和周长赋值的时候,程序直接崩溃,并且提示改属性不能赋值
from math import pi
class ReadOnlyError(Exception):
def __str__(self):
return 'Modify the read-only property'
class Circle:
def __init__(self, r):
self.r = r
self._perimeter = 0
self._area = 0
# perimeter
@property
def perimeter(self):
return self.r*pi*2
@perimeter.setter
def perimeter(self, value):
raise ReadOnlyError
# area
@property
def area(self):
return pi*self.r**2
@area.setter
def area(self, value):
raise ReadOnlyError
c1 = Circle(10)
print(c1.area, c1.perimeter)
c1.r = 3
print(c1.area, c1.perimeter)
三、歌词解析器
class Lyric:
def __init__(self, word):
self._time = 0
self.word = word
@property
def time(self):
return self._time
@time.setter
def time(self, value):
# value = '[00:45.99'
fen = float(value[1:3])
miao = float(value[4:])
self._time = fen*60 + miao
def __repr__(self):
return str(self.__dict__)
class LyricAnalysis:
def __init__(self, name):
self._name = name
self.__all_lyric = []
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
self.__all_lyric.clear()
def __analysis_file(self):
if not self.__all_lyric:
print('=========去解析歌词===============')
# 1.解析歌词文件中的内容
with open('files/%s.txt' % self.name, encoding='utf-8') as f:
while True:
# 读一行内容
line = f.readline()
# 切割字符串
lines = line.split(']') # ['[02:11.27', '[01:50.22', '[00:21.95', '穿过幽暗地岁月\n']
# 遍历时间创建歌词对象
for time_str in lines[:-1]:
lyric_obj = Lyric(lines[-1])
lyric_obj.time = time_str
# print(lyric_obj.__dict__)
self.__all_lyric.append(lyric_obj)
if not line:
break
# 2.对当前歌的歌词按时间排序
self.__all_lyric.sort(reverse=True, key=lambda item: item.time)
print(self.__all_lyric)
def get_world(self, time):
# 解析歌词文件
self.__analysis_file()
# 3.根据时间找对应的歌词
for item in self.__all_lyric:
if item.time < time:
return item.word
return '歌名'+self.name
l1 = LyricAnalysis('蓝莲花')
print(l1.get_world(30))
print(l1.get_world(10))
print(l1.get_world(10))
l1.name = '东风破'
print(l1.get_world(20))
print(l1.get_world(30))
print(l1.get_world(10))
print(l1.get_world(10))
四、运算符重载
python中所有的数据类型都是,数据都是对象。
所有的运算符对应的操作,本质都是在调用数据类型对应的魔法方法。(每个运算符都对应一个固定的魔法方法)
class Student(object):
def __init__(self, name, age=0, score=0):
self.name = name
self.age = age
self.score = score
def __repr__(self):
return str(self.__dict__)
# 重载加法预算符
# self + other = return 返回值
def __add__(self, other):
return self.age + other.age
# 重载乘法运算符
def __mul__(self, other):
return self.score * other
# >
def __gt__(self, other):
return self.score > other.score
# <
# def __lt__(self, other):
# return self.score < other.score
# 注意: >和<只需要重载一个
stu1 = Student('小明', 18, 60)
stu2 = Student('小花', 22, 80)
print(stu1 + stu2)
print(stu1 * 10)
print(stu1 > stu2)
print(stu1 < stu2)
all_students = [stu1, stu2, Student('小小', 17, 55), Student('xiaohong', 25, 70)]
all_students.sort()
print(all_students)
# 练习: 让Student的对象支持乘法运算,运算规则是:
# <name: 张三, age:10, score:0> * 3 = [<name: 张三, age:10, score:0> , <name: 张三, age:10, score:0> , <name: 张三, age:10, score:0> ]
五、深浅拷贝
import copy
class Dog:
def __init__(self, name, color='黄色'):
self.name = name
self.color = color
class Student:
def __init__(self, name, age=0, score=0):
self.name = name
self.age = age
self.score = score
self.dog = None
def __repr__(self):
return '<'+str(self.__dict__)[1:-1]+'>'
# *
def __mul__(self, other):
# self = stu1, other = 2
result = []
for _ in range(other):
result.append(self)
return result
stu1 = Student('张三', 18, 90)
print(stu1)
result = stu1 * 2
print(result)
stu1.name = '小明'
print(result)
result[0].name = '小花'
print(stu1, result)
1. 一个变量直接给另外一个变量赋值:直接将地址赋值,赋完后两个变量指向同一块内存区域,并且相互影响
stu2 = Student('Lisa', 18, 60)
stu3 = stu2
print(id(stu3), id(stu2))
stu2.age = 28
print(stu3)
2. 浅拷贝和深拷贝(面试点!)
拷贝原理: 将被拷贝的对象复制一份,产生一个新的数据,然后将新的数据的地址返回
a. 浅拷贝
- 列表或字典的copy方法是浅拷贝、切片也是浅拷贝
- copy.copy(对象) - 复制指定的对象,产生一个新的对象(不会复制子对象)
b. 深拷贝
copy.deepcopy(对象) - 复制指定的对象,产生一个新的对象。如果这个对象中有其他的对象,子对象也会被复制
print('======浅拷贝=====')
dog1 = Dog('财财')
stu2 = Student('Lisa', 18, 60)
stu2.dog = dog1
stu4 = copy.copy(stu2)
print('stu4:', stu4)
stu2.name = '小花'
print(stu2, stu4)
print('======深拷贝=====')
dog1 = Dog('财财')
stu2 = Student('Lisa', 18, 60)
stu2.dog = dog1
stu4 = copy.deepcopy(stu2)
print('stu4:', stu4)
stu2.name = '小花'
print(stu2, stu4)
六、内存管理
1.数据的存储(内存开辟)
"""
python的变量都存储在栈区间,对象都在堆区间。
声明变量或者给变量赋值,是先在内存(堆)中开辟存储数据,然后将数据地址保存在变量中。
但是数字和字符串特殊,如果是用数字或者字符串给变量赋值,不会直接开辟空间保存数据,
而是先在内存检测这个数据之前是否已经存储过,如果已经存储直接用上次保存的数据,没有存储才会开辟新的空间保存数据
"""
2. 内存的释放
"""
1)引用计数
python每个对象都有一个属性叫引用计数,用来保存当前对象的引用的个数。
python中的垃圾回收机制来判断一个对象是否销毁,就看这个对象的引用计数是否为零,如果为零就会被销毁。
"""
from sys import getrefcount
list1 = [1, 2]
list2 = [1, 2]
print(id(list1), id(list2))
num1 = 10
num2 = 10
print(id(num1), id(num2))
class Student:
def __init__(self):
self.name = '张三'
print('==============引用计数===========')
list1 = [1, 2]
print(getrefcount(list1))
# def yt_getrefcount(obj):
# # obj = list1
# return 获取obj对应的数据的引用个数
# yt_getrefcount(list1)
# 让引用计数增加
list2 = list1
print(getrefcount(list1))
dict1 = {'a': list2}
print(getrefcount(list1))
#
# num = 100
# print(getrefcount(num))
# num1 = 100
# print(getrefcount(num))
# 让引用计数减少
print(getrefcount(list1))
list2 = 100
print(getrefcount(list1))
del dict1['a']
print(getrefcount(list1))
del list1
# print(getrefcount(list1))
print('===========函数体调用和函数体类调用===========')
list1 = [1, 3]
# list2 = list1
def f1(list1):
print(getrefcount(list1))
print('函数1')
def f2(list1, lis):
# lis = list1
# list3 = list1
f1(list1)
print(getrefcount(list1)) # lis = list1
print('函数2')
f1(list1)
# f2(list1)
f2(list1, list1)
# f2(list1,list1)
print(getrefcount(list1))
七、socket套接字
1. 服务器创建
"""
进行通信通信的两端就是套接字;有两种类型,分别是服务器套接字、客户端套接字
"""
# 1.创建套接字对象(买个电话机)
"""
family - 设置ip协议类型, AF_INET(ipv4), AF_INET6(ipv6)
type - 设置传输协议类型, SOCK_STREAM(TCP), SOCK_DGRAM(UDP)
"""
server = socket(family=AF_INET, type=SOCK_STREAM)
# 2.绑定ip地址和端口(插电话线绑定电话号码)
"""
bind((ip地址, 端口))
ip地址 - 字符串,服务器对应的ip地址
端口号 - int, 端口号用来区分一台电脑上的不同的服务。0-65535, 0-1024是著名端口,一般不选。
同一时间一个端口只能绑定一个服务
"""
addr = ('10.7.185.82', 8085)
server.bind(addr)
# 3.开始监听请求(按电池,等别人打电话)
server.listen(512)
# 4.让服务器一直运行
while True:
print('监听状态....')
# 5.接收请求(接电话)
# 代码运行到这个位置,会停下来,等到有客户端给服务器发送请求为止。。。
connect, addr = server.accept()
print(addr, '连接成功!')
while True:
# 6.接收数据(听别人说)
"""
recv(bufsize) - bufsize,设置一次性能够接收的数据大小的最大值,单位是字节
返回的数据类型是字节
"""
# print('接收消息前')
re_data = connect.recv(1024)
print(re_data.decode(encoding='utf-8'))
# print('接收消息后')
# 7.发送数据 (说给别人听)
message = input('>>>')
connect.send(message.encode())
# 8.关闭连接(挂电话)
connect.close()
2. 客户端创建
from socket import *
# 1.创建套接字对象
client = socket()
# 2.连接服务器
client.connect(('10.7.185.86', 8087))
while True:
# 3.发送消息
message = input('请输入:')
client.send(message.encode())
# 4.接收消息
re_data = client.recv(1024)
print(re_data.decode(encoding='utf-8'))