day16_內(nèi)存管理和套接字

前言回顧

1.私有化: 命名的時(shí)候兩個(gè)下劃線開頭

只能是__age,而不是__age__(后者依舊能訪問(wèn))

2.getter和setter
getter - 想要[獲取]屬性之前做點(diǎn)別的事情
setter - 想要給屬性[賦值]的時(shí)候做別的事情

  1. 屬性名前加一個(gè)'_'
  2. 添加getter
@property
def getter名(self):
    做別的事情
    return 值
  1. 添加setter
@getter名.setter
def setter名(self, 參數(shù)):
    做別的事情
    給屬性賦值

3.方法

  1. 對(duì)象方法
    怎么聲明:直接聲明在類中的函數(shù)
    特點(diǎn):有默認(rèn)參數(shù)self,不需要傳參,指向當(dāng)前對(duì)象
    怎么調(diào)用:對(duì)象調(diào)用
    什么時(shí)候:實(shí)現(xiàn)函數(shù)的功能[需要]對(duì)象的屬性

  2. 類方法
    怎么聲明:聲明函數(shù)前加@classmethod
    特點(diǎn):有默認(rèn)函數(shù)cls,不需要傳參,指向當(dāng)前類
    怎么調(diào)用:類調(diào)用
    什么時(shí)候:實(shí)現(xiàn)函數(shù)的功能[不需要]對(duì)象的屬性的前提下需要類的字段

  3. 靜態(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; 并且支持多繼承
繼承就是讓子類直接擁有

  1. 子類添加內(nèi)容
    字段和方法直接聲明
    添加對(duì)象屬性

  2. 重寫方法

注意:多繼承的時(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.淺拷貝

  1. 列表或字典的copy方法是淺拷貝、切片也是淺拷貝
  2. 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)存的釋放

  1. 引用計(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'))
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容