前言回顧
1.私有化: 命名的時(shí)候兩個(gè)下劃線開頭
只能是__age,而不是__age__(后者依舊能訪問(wèn))
2.getter和setter
getter - 想要[獲取]屬性之前做點(diǎn)別的事情
setter - 想要給屬性[賦值]的時(shí)候做別的事情
- 屬性名前加一個(gè)'_'
- 添加getter
@property
def getter名(self):
做別的事情
return 值
- 添加setter
@getter名.setter
def setter名(self, 參數(shù)):
做別的事情
給屬性賦值
3.方法
對(duì)象方法
怎么聲明:直接聲明在類中的函數(shù)
特點(diǎn):有默認(rèn)參數(shù)self,不需要傳參,指向當(dāng)前對(duì)象
怎么調(diào)用:對(duì)象調(diào)用
什么時(shí)候:實(shí)現(xiàn)函數(shù)的功能[需要]對(duì)象的屬性類方法
怎么聲明:聲明函數(shù)前加@classmethod
特點(diǎn):有默認(rèn)函數(shù)cls,不需要傳參,指向當(dāng)前類
怎么調(diào)用:類調(diào)用
什么時(shí)候:實(shí)現(xiàn)函數(shù)的功能[不需要]對(duì)象的屬性的前提下需要類的字段靜態(tài)方法
怎么聲明:聲明函數(shù)前加@staticmethod
特點(diǎn):沒(méi)有默認(rèn)參數(shù)(和普通函數(shù)一樣)
怎么調(diào)用:類調(diào)用
什么時(shí)候:實(shí)現(xiàn)函數(shù)的功能既不需要對(duì)象屬性也不需要類的字段
4.繼承
python支持繼承語(yǔ)法,默認(rèn)的類都是繼承object; 并且支持多繼承
繼承就是讓子類直接擁有
子類添加內(nèi)容
字段和方法直接聲明
添加對(duì)象屬性重寫方法
注意:多繼承的時(shí)候可以繼承多個(gè)類的方法和字段,但是只能繼承第一個(gè)父類的屬性
(故一般不采用多繼承)
class Person:
def __init__(self, name, age=0):
self.name = name
self.age = age
self.gender = '女'
def show(self):
print('姓名:%s 年齡:%s' % (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 年齡:%s 分?jǐn)?shù):%d' % (self.name, self.age, self.score))
stu = Student('小明', 90, 20)
print(stu.__dict__)
stu.show()
多繼承(重寫方法)
class Animal(object):
def __init__(self):
self.age = 0
self.weight = 10
@staticmethod
def eat(food):
print('動(dòng)物吃%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)
作業(yè)
from math import pi
1.建立一個(gè)汽車類Auto,包括輪胎個(gè)數(shù),汽車顏色,車身重量,速度等屬性,
并通過(guò)不同的構(gòu)造方法創(chuàng)建實(shí)例。至少要求汽車能夠加速 減速 停車。
再定義一個(gè)小汽車類CarAuto繼承Auto并添加空調(diào)、CD屬性,
并且重新實(shí)現(xiàn)方法覆蓋加速、減速的方法
class Auto:
def __init__(self, color='白色', weight=50, speed=0):
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=0):
super().__init__(color, weight, speed)
self.air_conditioner = '格力'
self.CD = ''
c1 = CarAuto('紅色')
print(c1.__dict__)
2.創(chuàng)建一個(gè)Person類,添加一個(gè)類字段用來(lái)統(tǒng)計(jì)Person類的對(duì)象的個(gè)數(shù)
# 創(chuàng)建對(duì)象一定會(huì)調(diào)用__init__方法,故統(tǒng)計(jì)方法的使用次數(shù)即可
class Person:
count = 0
def __init__(self):
Person.count += 1
# for i in range(10):
# Person()
# print(Person.count)
3.創(chuàng)建一個(gè)動(dòng)物類,擁有屬性:性別、年齡、顏色、類型 ,要求打印這個(gè)類的對(duì)象的時(shí)候以'/XXX的對(duì)象: 性別-? 年齡-? 顏色-? 類型-?/'的形式來(lái)打印
class Animal:
"""動(dòng)物類"""
def __init__(self, gender='公', age=1, color='黑色', type1='爬行'):
self.gender = gender
self.age = age
self.color = color
self.type = type1
def __repr__(self):
return '/%s的對(duì)象: 性別-%s 年齡-%d 顏色-%s 類型-%s/' % (self.__class__.__name__, self.gender, self.age, self.color, self.type)
an1 = Animal('公', 3, '棕色', '哺乳')
print(an1)
4.寫一個(gè)圓類, 擁有屬性半徑、面積和周長(zhǎng);要求獲取面積和周長(zhǎng)的時(shí)候的時(shí)候可以根據(jù)半徑的值把對(duì)應(yīng)的值取到。
但是給面積和周長(zhǎng)賦值的時(shí)候,程序直接崩潰,并且提示改屬性不能賦值
class ReadOnlyError(Exception):
def __str__(self):
return '屬性不能賦值!'
class Circle:
"""圓類"""
def __init__(self, radius):
self.radius = radius
self._perimeter = 0
self._area = 0
# perimeter
@property
def perimeter(self):
return self.radius*pi*2
@perimeter.setter
def perimeter(self, value):
raise ReadOnlyError
# area
@property
def area(self):
return self.radius**2*pi
@area.setter
def area(self, value):
raise ReadOnlyError
歌詞解析
5.(嘗試)寫一個(gè)類,其功能是:
1.解析指定的歌詞文件的內(nèi)容
2.按時(shí)間顯示歌詞
提示:歌詞文件的內(nèi)容一般是按下面的格式進(jìn)行存儲(chǔ)的。
歌詞前面對(duì)應(yīng)的是時(shí)間,在對(duì)應(yīng)的時(shí)間點(diǎn)可以顯示對(duì)應(yīng)的歌詞
# 直接賦值是不會(huì)經(jīng)過(guò)getter和setter的,故不要用參數(shù)
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.解析歌詞文件中的內(nèi)容
with open('files/%s.txt' % self.name, encoding='utf-8') as f:
while True:
# 讀一行內(nèi)容
line = f.readline()
# 切割字符串
lines = line.split(']')
# 遍歷時(shí)間創(chuàng)建歌詞對(duì)象
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.對(duì)當(dāng)前歌的歌詞進(jìn)行時(shí)間排序
self.__all_lyric.sort(reverse=True, key=lambda item: item.time)
print(self.__all_lyric)
def get_word(self, time):
# 解析歌詞文件
self.__analysis_file()
# 3.根據(jù)時(shí)間找對(duì)應(yīng)的歌詞
for item in self.__all_lyric:
if item.time < time:
return item.word
return '歌名'+self.name
l1 = LyricAnalysis('藍(lán)蓮花')
print(l1.get_word(30))
print(l1.get_word(40))
print(l1.get_word(10))
l1.name = '東風(fēng)破'
print(l1.get_word(20))
print(l1.get_word(30))
print(l1.get_word(10))
print(l1.get_word(10))
運(yùn)算符
python中所有的數(shù)據(jù)類型都是類,數(shù)據(jù)都是對(duì)象
所有的運(yùn)算符對(duì)應(yīng)的操作,本質(zhì)都是在調(diào)用數(shù)據(jù)類型對(duì)應(yīng)的魔法方法 (每個(gè)運(yùn)算符都對(duì)應(yīng)一個(gè)固定的魔法方法)
class Student:
def __init__(self, name, age=0, score=0):
self.name = name
self.age = age
self.score = score
def __repr__(self):
return str(self.__dict__)
# 重載加法運(yùn)算符
# self + other = return 返回值 (other是任意數(shù)據(jù),可以是對(duì)象,可以是int...)
def __add__(self, other):
return self.age + other.age
# 重載乘法運(yùn)算符
def __mul__(self, other: int):
return self.score * other
# >
# def __gt__(self, other):
# return self.score > other.score
# <
def __lt__(self, other):
return self.score < other.score
# 注意:>和<只需要重載一個(gè)(因?yàn)榱硪粋€(gè)它可以取反)
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('二狗', 18, 70)]
all_students.sort()
print(all_students)
練習(xí):讓Student的對(duì)象支持乘法運(yùn)算,運(yùn)算規(guī)則是:
<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
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)
copy
深拷貝和淺拷貝
直接賦值
1.一個(gè)變量直接給另外一個(gè)變量賦值:直接將地址賦值,賦完后兩個(gè)變量指向同一塊內(nèi)存區(qū)域,并且相互影響
stu2 = Student('Lisa', 18, 60)
stu3 = stu2
print(id(stu2), id(stu3))
stu2.age = 28
print(stu3)
2.淺拷貝和深拷貝(面試點(diǎn)!)
拷貝原理:將被拷貝的對(duì)象復(fù)制一份,產(chǎn)生一個(gè)新的數(shù)據(jù),然后將新的數(shù)據(jù)的地址返回
a.淺拷貝
- 列表或字典的copy方法是淺拷貝、切片也是淺拷貝
- copy.copy(對(duì)象) - 復(fù)制指定的對(duì)象,產(chǎn)生一個(gè)新的對(duì)象 (不會(huì)復(fù)制子對(duì)象)
b.深拷貝
copy.deepcopy(對(duì)象) - 復(fù)制指定的對(duì)象,產(chǎn)生一個(gè)新的對(duì)象 如果這個(gè)對(duì)象中有其他的對(duì)象,子對(duì)象也會(huì)被復(fù)制
淺拷貝
dog1 = Dog('財(cái)財(cái)')
stu2 = Student('Lisa', 18, 60)
stu4 = copy.copy(stu2)
print(stu4)
stu2.name = '小花'
print(stu2)
print(stu4)
# 淺拷貝
# list1 = [1, 2, 3, 4]
# list2 = list1.copy()
# list1.append(6)
# print(list2)
深拷貝
stu2 = Student('Lisa', 18, 60)
stu4 = copy.deepcopy(stu2)
print(stu4)
stu2.name = '小花'
print(stu2)
print(stu4)
存儲(chǔ)器
from sys import getrefcount
棧區(qū)間 -> 自動(dòng)開辟自動(dòng)釋放
堆區(qū)間 -> 手動(dòng)開辟手動(dòng)釋放
棧區(qū)間:變量 堆區(qū)間:對(duì)象(數(shù)據(jù))
1.數(shù)據(jù)的存儲(chǔ)(內(nèi)存開辟)
python的變量都存儲(chǔ)在棧區(qū)間,對(duì)象都在堆區(qū)間
聲明變量或者給變量賦值,是先在內(nèi)存(堆)中開辟空間存儲(chǔ)數(shù)據(jù),然后將數(shù)據(jù)地址保存在變量中
注意:但是數(shù)字和字符串特殊,如果是用數(shù)字或者字符串給變量賦值,不會(huì)直接開辟空間保存數(shù)據(jù),
而是先在內(nèi)存檢測(cè)這個(gè)數(shù)據(jù)之前是否已經(jīng)存儲(chǔ)過(guò),如果已經(jīng)存儲(chǔ)過(guò)直接用上次保存的數(shù)據(jù),沒(méi)有存儲(chǔ)過(guò)的才會(huì)開辟新的空間保存數(shù)據(jù)
list1 = [1, 2]
list2 = [1, 2]
print(id(list1), id(list2))
# 上面list1和list2的內(nèi)存地址不同
num1 = 10
num2 = 10
print(id(num1), id(num2))
# num1和num2的內(nèi)存地址相同
2.內(nèi)存的釋放
引用計(jì)數(shù)
python每個(gè)對(duì)象都有一個(gè)屬性叫引用計(jì)數(shù),用來(lái)保存當(dāng)前對(duì)象的引用的個(gè)數(shù)
python中的垃圾回收機(jī)制來(lái)判斷一個(gè)對(duì)象是否銷毀,就看這個(gè)對(duì)象的引用計(jì)數(shù)是否為零,如果為零就會(huì)被銷毀
class Student:
def __init__(self):
self.name = '張三'
# Student() 沒(méi)有引用計(jì)數(shù),創(chuàng)建后就被銷毀了
print('===引用計(jì)數(shù)===')
list1 = [1, 2]
print(getrefcount(list1)) # 結(jié)果為2,因?yàn)間etrefcount(obj),obj為臨時(shí)的引用,會(huì)增加個(gè)數(shù)
# def my_getrefcount(obj):
# return 獲取obj對(duì)應(yīng)的數(shù)據(jù)的引用個(gè)數(shù)
# my_getrefcount(list1)
# 讓引用計(jì)數(shù)增加
list2 = list1
print(getrefcount(list1))
dict1 = {'a': list1}
print(getrefcount(list1))
num1 = 100
print(getrefcount(num1))
num2 = 100
print(getrefcount(num1))
# 讓引用計(jì)數(shù)減少
print(getrefcount(list1))
list2 = 100
print(getrefcount(list1))
del dict1['a']
print(getrefcount(list1))
del list1
# print(getrefcount(list1))
套接字
server
# from socket import socket,AF_INET
from socket import *
進(jìn)行通信的兩端就是套接字;有兩種類型,分別是服務(wù)器套接字、客戶端套接字
1.創(chuàng)建套接字對(duì)象(買個(gè)電話機(jī))
socket(family= , type= )
family - 設(shè)置ip協(xié)議類型,AF_INET(ipv4), AF_INET(ipv6)
type - 設(shè)置傳輸協(xié)議類型,SOCK_STREAM(TCP), SOCK_DGRAM(UDP)
server = socket(family=AF_INET, type=SOCK_STREAM)
2.綁定ip地址和端口(插電話線綁定電話號(hào)碼)
bind((ip地址, 端口))
ip地址 - 字符串,服務(wù)器對(duì)應(yīng)的ip地址
端口號(hào) - int,端口號(hào)用來(lái)區(qū)分客戶端(電腦、手機(jī))上的不同的服務(wù) 0-65535,0-1024是著名端口(一般不選)
同一時(shí)間一個(gè)端口只能綁定一個(gè)服務(wù)
addr = ('127.0.0.1', 8080)
server.bind(addr)
3.開始監(jiān)聽請(qǐng)求(安電池,等別人打電話)
server.listen(512) # 監(jiān)聽個(gè)數(shù)
4.讓服務(wù)器一直運(yùn)行
while True:
print('監(jiān)聽狀態(tài)...')
# 5.接收請(qǐng)求(接電話)
# 代碼運(yùn)行到這個(gè)位置,會(huì)停下來(lái),等到有客戶端給服務(wù)器發(fā)送請(qǐng)求為止...
connect, addr = server.accept()
print(addr, '連接成功')
while True:
# 6.接收數(shù)據(jù)(聽別人說(shuō))
"""
recv(bufsize) - bufsize,設(shè)置一次性能夠接收的數(shù)據(jù)大小的最大值
返回的數(shù)據(jù)類型是字節(jié)
"""
print('接收消息前')
re_data = connect.recv(1024)
print(re_data.decode(encoding='utf-8'))
print('接收消息后')
# 7.發(fā)送數(shù)據(jù)(說(shuō)給別人聽)
value = input('>>>')
connect.send(value.encode()) # 發(fā)送的數(shù)據(jù)必須是二進(jìn)制
# 8.關(guān)閉連接(掛電話)
connect.close()
client
from socket import *
1.創(chuàng)建套接字對(duì)象
client = socket()
2.連接服務(wù)器
client.connect(('10.7.185.92', 8080))
while True:
# 3.發(fā)送消息
message = input('請(qǐng)輸入:')
client.send(message.encode())
# 4.接收消息
re_data = client.recv(1024)
print(re_data.decode(encoding='utf-8'))