1.類的繼承
python中類 支持繼承,并且支持多繼承()
1.什么是繼承
父類(超類):被繼承的類
子類:繼承的類,去繼承父類的類
繼承就是讓子類直接擁有父類的屬性和方法(注意:繼承后父類的東西不會減少)
python中所有的類都是直接或者間接的繼承自object
2.怎么繼承
class 類名(父類):
class 類名:== class 類名(object)
3.能繼承那些東西
對象屬性,對象方法,類的字段,類方法,靜態方法都可以繼承
注意:如果設置了slots會約束了當前對象屬性,并且會導致當前類的dict屬性不存在
繼承后,slots不會約束到子類的對象屬性,但是會導致子類對象的dict
只有在繼承后當前的類中新添加的屬性才能被dict檢測到
代碼示例
class Person(object):
num = 61
__number = 61
def __init__(self, name='小明', age=0):
self.name = name
self.age = age
self.__sex = ''
def eat(self, food: str):
print('再吃%s' % food)
@staticmethod
def func1():
print('Person的靜態方法')
@classmethod
def show_num(cls):
print('%d' % cls.num)
class Student(Person):
pass
# 創建對象
stu = Student()
print(stu.name, stu.age)
stu.eat('面條')
Student.func1()
Student.show_num()
print(stu.__dict__)
運行結果
小明 0
再吃面條
Person的靜態方法
61
{'name': '小明', 'age': 0, '_Person__sex': ''}
2.重寫
繼承后子類 會擁有父類的屬性和方法,也可以添加屬于自己的屬性和方法
1.添加新的方法
直接在子類中聲明新的方法,新的方法只能通過子類來使用
2.重寫
a.子類繼承父類的方法,在子類中去重新實現這個方法的功能 ---> 完全重寫
b.在子類中方法中通過super().父類方法保留父類對應的方法的功能
3.類中的函數的調用過程
類.方法(),對象.方法()
先看當前類是否有這個方法,如果有就直接調用當前類中相應的方法。如果沒有就去當前類的父類中
有沒有這個方法,如果有就調用父類的方法,如果父類中也沒有,再去父類的父類找,直到找到為止,
如果找到基類object還沒有找到就出現異常
代碼示例
class Person:
def __init__(self, name=''):
self.name = name
def eat(self, food):
print('%s再吃%s' % (self.name, food))
@staticmethod
def run():
print('人在跑步')
@classmethod
def get_up(cls):
print('洗漱')
print('換衣服')
class Student(Person):
def study(self):
print('%s在學習' % self.name)
def eat(self, food):
# super():當前類的父類的對象
print('對象方法', super(), super)
super().eat(food)
print('喝一杯牛奶')
@staticmethod
def run():
print('學生在跑步')
@classmethod
def get_up(cls):
# super() --> 獲取當前類的父類
# super().get_up() --> 調用父類的get_up方法
print('類方法', super(), super)
super().get_up()
# cls.__bases__[0].get_up()
print('背書包')
stu = Student()
stu.study()
Student.run()
print('=========')
Student.get_up()
stu.name = '小紅'
stu.eat('面包')
運行結果
在學習
學生在跑步
=========
類方法 <super: <class 'Student'>, <Student object>> <class 'super'>
洗漱
換衣服
背書包
對象方法 <super: <class 'Student'>, <Student object>> <class 'super'>
小紅再吃面包
喝一杯牛奶
3.添加屬性
添加屬性
1.添加字段
就直接在子類中聲明新的字段
2.添加對象屬性
子類是通過繼承父類的init來繼承的父類的對象屬性
代碼示例
class Car:
num = 10
def __init__(self, color):
self.color = color
self.price = 10
class SportsCar(Car):
# 修改字段默認值
num = 8
# 添加字段
weel_count = 4
# 給子類添加新的對象屬性
def __init__(self, color, horsepower):
# 通過super()去調用父類的init方法,用來繼承父類的對象屬性
super().__init__(color)
self.horsepower = horsepower
print(Car.num)
SportsCar.num = 19
print(SportsCar.num, SportsCar.weel_count)
當子類沒有聲明init方法,通過子類的構造方法創建對象的時候會自動調用父類的init方法
sp1 = SportsCar('白色', 4)
print(sp1.color)
print(sp1.__dict__)
print(sp1.horsepower)
運行結果
10
19 4
白色
{'color': '白色', 'price': 10, 'horsepower': 4}
4
練習
練習:聲明一個Person類,有屬性名字、年齡和身份證號碼。要求創建Person的時候
必須給名字賦值,年齡和身份證可以賦值也可以不賦
聲明一個學生類、有屬性名字、年齡、身份證號碼和學號,成績(用繼承)
要求創建學生的時候,必須給學號賦值,可以給年齡,名字賦值,不能給身份證號、成績賦值
代碼如下
class Person:
def __init__(self, name, age=0, id='0000'):
self.name = name
self.age = age
self.id = id
class Student(Person):
def __init__(self, sno, age=0, name=''):
self.sno = sno
self.score = '45'
super().__init__(name, age)
Person('小明')
Person('小紅', 45)
Person('小紅', 45, '0001')
Student('01')
Student('01', name='小華')
Student('01', 18, name='小華')
4.運算符的重載
運算符重載:通過實現類相應的魔法方法,來讓類的對象支持相應的運算符(+,-,>,<等)
值1 運算符 值2 ----> 值1.魔法方法(值2)
代碼示例
import copy
import random
10 > 20 # int類,實現 > 對應的魔法方法 __gt__
class Student:
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
# __gt__就是 > 對應的魔法方法
def __gt__(self, other):
# self -> 指的是大于符號前面的值,other -> 指的是大于符號后面的值
print(self.name, other.name)
return self.age > other.age
# 小于符號對應的魔法方法,
# 注意:__gt__和__lt__兩個方法只需要實現一個就可以了
# def __lt__(self, other):
# return self.age < other.age
def __add__(self, other):
return [self.name, other.name]
def __mul__(self, other):
result = []
for _ in range(other):
result.append(copy.copy(self))
return result
stu = Student('夏普', 23, 65)
stu1 = Student('選舉', 56, 88)
print(stu > stu1)
print(stu < stu1)
print(stu + stu1)
student = stu * 10
print(student)
for stu in student:
print(stu.name)
class Person:
def __init__(self, name='張三', age=0):
self.name = name
self.age = age
def __mul__(self, other):
result = []
for _ in range(other):
result.append(copy.copy(self))
return result
def __gt__(self, other):
return self.age > other.age
# 定制打印格式
def __repr__(self):
return str(self.__dict__)[1:-1]
p1 = Person() * 10
for p in p1:
p.age = random.randint(15, 35)
print(p1)
# 列表元素是類的對象,對列表進行排序
p1.sort()
print(p1)
print(max(p1))
class Dog:
def __init__(self, name):
self.name = name
def __mul__(self, other):
result = []
for _ in range(other):
result.append(copy.copy(self))
return result
運行結果
夏普 選舉
False
選舉 夏普
True
['夏普', '選舉']
[<__main__.Student object at 0x0000029CCDE3CBE0>, <__main__.Student object at 0x0000029CCDEB7320>, <__main__.Student object at 0x0000029CCDEB72E8>, <__main__.Student object at 0x0000029CCDEC0978>, <__main__.Student object at 0x0000029CCDEC0668>, <__main__.Student object at 0x0000029CCDEC0208>, <__main__.Student object at 0x0000029CCDEC06A0>, <__main__.Student object at 0x0000029CCDEC0940>, <__main__.Student object at 0x0000029CCDEC07F0>, <__main__.Student object at 0x0000029CCDEC0828>]
夏普
夏普
夏普
夏普
夏普
夏普
夏普
夏普
夏普
夏普
['name': '張三', 'age': 22, 'name': '張三', 'age': 29, 'name': '張三', 'age': 26, 'name': '張三', 'age': 23, 'name': '張三', 'age': 34, 'name': '張三', 'age': 28, 'name': '張三', 'age': 17, 'name': '張三', 'age': 16, 'name': '張三', 'age': 22, 'name': '張三', 'age': 15]
['name': '張三', 'age': 15, 'name': '張三', 'age': 16, 'name': '張三', 'age': 17, 'name': '張三', 'age': 22, 'name': '張三', 'age': 22, 'name': '張三', 'age': 23, 'name': '張三', 'age': 26, 'name': '張三', 'age': 28, 'name': '張三', 'age': 29, 'name': '張三', 'age': 34]
'name': '張三', 'age': 34
5.內存管理機制
python中的內存管理 --> 自動管理 ---> 垃圾回收機制
內存結構中分棧區間和堆區間,棧區間中的內存是系統自動開啟自動釋放
堆區間的內存需要手動申請,手動釋放
但是目前絕大部分編程語言都提供了一套屬于自己的關于堆中的內存管理方案
----> python中垃圾回收機制是用來管理堆中的內存的釋放
python中的數據都是存在堆中的,數據的地址都是在棧區間。
1.內存的開辟
python中將值賦給變量的時候,會先在堆中開辟空間將數據存儲起來,然后在數據對應的地址返回給變量,存在棧中
但是如果是數字和字符串,會先在緩存區中查看這個數據之前是否已經創建過,如果沒有就去創建空間存數據,
然后將地址返回,如果之前已經創建過,就直接將之前的地址返回
2.內存的釋放 ---> 垃圾回收機制
系統每隔一定的時間就會去檢測當前程序中所有的對象的引用計數值是否為0,如果對象的引用計數
為0,對象對應的內存就會被銷毀,如果不是就不會被銷毀
3.引用計數
每一個對象都有一個引用計數的屬性,用來存儲當前對象被引用的次數。可以通過sys模塊中的getrefcount
去獲取一個對象的引用計數值
增加引用計數:
代碼示例
from sys import getrefcount
s1 = 100
s2 = 100
print(id(s1), id(s2))
s1 = 99
print(id(s1), id(s2))
aaa = [1, 2]
print(getrefcount(aaa))
b = 10
print(getrefcount(b))
c = 10
print(getrefcount(c))
增加引用計數:增加引用(增加保存當前對象地址的變量的個數)
a1 = ['abc']
b1 = a1
list1 = [a1, 100]
print(getrefcount(a1))
2.減少引用計數
del b1 # 刪除存儲對象地址的變量
list1[0] = 1 # 修改存儲對象地址變量的值
print(getrefcount(a1))
運行結果
1471117424 1471117424
1471117392 1471117424
2
18
19
4
2
6.認識pygame
pygame是一個用python寫2D游戲的第三方庫
代碼示例
import pygame
# 1.初始化游戲
pygame.init()
# 2.創建游戲窗口
screen = pygame.display.set_mode((480, 700))
# 顯示圖片
image = pygame.image.load('image/d.jpg') # ---> 打開一張圖片,返回圖片對象
"""
窗口.blit(圖片對象,位置) ---> 坐標:(x, y)
"""
screen.blit(image, (0, 0))
pygame.display.flip() # 將數據展示在窗口上
# 3.創建游戲循環
flag = True
while flag:
for event in pygame.event.get(): # 獲取事件
if event.type == pygame.QUIT:
print('點了關閉按鈕')
# flag = False
exit() # 結束程序(結束線程)