(一) 类属性和实例属性
1.定义
类属性:是类拥有的属性,它被类对象的实例对象的实例对象所共有的,在内存中只有一个内存。
实例属性(对象属性):实例化对象所拥有的属性(有多少个对象,就有多少份属性)
类方法:是类拥有的方法,它被类的对象所调用。
当对象没有所具有的属性时,调用类的属性
调用person1 ,person2 , person3的country 属性,当对象没有country属性的时候调用类的country属性,当对象有country 属性的时候,调用自己的country 属性
运行结果如下:
实例属性(对象属性):
实验代码如下:
self.name , self.age , self.gender 都是实例属性(有多少个对象,就存储多少个)
运行结果如下:
ps: 此处由于运用的编译工具具有自优化功能,因此,此处的地址显示的是一样的。其实应该是每一个年龄对应一个地址。(可以在Linux 中实现)
2.类属性与类方法不同点:(具体见下表)
(1)定义方面
(2) 工作占用的内存不一样
(3) 调用的方法不一样
类属性 | 对象属性 |
---|---|
定义类属性直接定义在里面 | 定义时要与对象要与对象绑在一起 |
工作的内存只存一份,与对象的个数无关 | 内存占用有多少个对象就存储多少份 |
调用方法为:类名.属性名 或 对象名.属性名 | 调用方法为:对象名.属性名 |
(二)类方法,实例方法,静态方法
1.定义
实例方法: 默认传递的第一个参数是实例对象。该参数一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法),调用:只能由实例对象调用
类方法:默认传递的第一个参数是当前的类 使用装饰器@classmethod,该参数名一般约定为“cls”class的缩写,调用: 实例对象和类对象都能调用
静态方法:使用装饰器@staticmethod,参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法; 调用: 实例对象和类对象都能调用
2.使用方法
1)类方法:第一个参数必须是类对象,且cls 是形参,可以修改成其他变量名,但一般都用‘cls’
并且,类方法可以通过实例对象和类对象去访问
2)静态方法:一般会用装饰器 @staticmethod来标识为静态方法,静态放法不需要多定义参数,且能通过实例对象和类对象去访问
eg .
类方法的应用:
class Date(object):
def __init__(self, year=2019, month=6, day=17):
self.year = year
self.month = month
self.day = day
def echo(self):
print("%s--%s--%s" % (self.year, self.month, self.day))
@classmethod
def as_string(cls, str):
month, day, year = str.split('/')
d1 = cls(year, month, day)
return d1
d = Date()
d.echo()
str = '3/17/2019'
d1 = Date.as_string(str)
d1.echo()
运行结果为:
第一个结果是因为,在第一次调用的时候没有定义值,因此返回的就是默认值。
第二个结果在调用,有自己赋予值,因此返回的是调用后的结果。
静态方法的应用:
class Date(object):
def __init__(self, year=2019, month=6, day=17):
self.year = year
self.month = month
self.day = day
def echo(self):
print("%s--%s--%s" % (self.year, self.month, self.day))
@staticmethod
def is_vaild(str):
month, day, year = map(int, str.split('/'))
return year>0 and 0<month <= 12 and 0 < day <= 31
d = Date()
d.echo()
print(Date.is_vaild('17/13/2019'))
运行结果为:
第一个结果是因为,在第一次调用的时候没有定义值,因此返回的就是默认值。
第二个结果是判断输入的年月日是否为合法的。
(三) property 属性
1) python内置的 @property 装饰器就是负责把一个方法变成属性调用的
2) @property 本身又创建了另一个装饰器@state.setter ,负责把一个setter 方法变成属性赋值,于是,我们就拥有了一个可控的属性操作
3) @property 广泛应用于类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样程序运行的过程中就减少了很多出错的可能性
eg:
import time
class Date(object):
def __init__(self, year=None, month=None, day=None):
self._year = year
self._month = month
self._day = day
# 类属性 :获取类属性的方法: 对象名.属性名
@property
def month(self):
if 0 < self._month < 12:
return self._month
# 设置属性装饰器,当设置属性时简洁: 对象名.属性名 = 新的值
@month.setter
def month(self, month):
if 0 < self._month <= 12:
self._month = month
return True
# 就删除属性装饰器,当删除时 简洁: del 对象名.属性名
@month.deleter
def month(self):
del self._month
d = Date(2019, 10, 10)
print(d.month)
d.month = 3
print("正在修改月份")
print(d.month)
del d.month
print("正在删除月份")
运行结果为:
(四)单例模式
- 定义: 单例模式是一个类只能构建一个对象的设计模式
- 如何理解: 实际上就是在打开一个文件的时候,打开一个就会弹出一个会话框,但要是每一次打开的都是同一个文件,那么要是一个文件打开多次,就会在不同的会话框显示就会使使用者混乱,不清楚到底哪个爱是真实的状态,并不方便我们的使用,因此要采用单例模式。eg: 一个系统只能有一个窗口管理或者是文件系统。
- 单例模式的实现方法 ——装饰器:@singleton
@singleton 是用来装饰类的装饰器: 在实例化类时,只实例化 一个对象
eg:在学生名单中添加学生
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls in instances:
return instances[cls]
else:
obj = cls(*args, **kwargs)
instances[cls] = obj
return obj
return wrapper
@singleton
class Student(object):
pass
s1 = Student()
s2 = Student()
print(s1, s2)
运行结果为:
ps :如果没有运用单例模式的装饰器,那么打印出来的s1和s2 的存储地址是不同的,即使他们里面的东西是相同的。 因此使用单例模式,就可以避免这个问题
(五)应用
1.小游戏设计 ————聪聪吃热狗(单人版 , 双人版)
游戏简述:一款聪聪吃热狗游戏,你可以自己调节通过↑↓←→控制聪聪的位置, 聪聪移动时会消耗能量 10, 游戏中吃到热狗分数加1, 能量加20,最后的目标就是称霸世界咯, 吃掉 所有的热狗即游戏胜利。王思聪能量消耗完毕即游戏失败。
游戏目标: 不断的吃掉热狗,不断的强大起来吧
实验代码:
import random
import time
import pygame
import sys
from pygame.locals import *
width = 640
height = 480
pygame.init()
screen = pygame.display.set_mode([width, height])
pygame.display.set_caption('聪聪吃热狗')
# 设置背景
background = pygame.image.load("./img/bg.jpg").convert_alpha()
congImg = pygame.image.load("./img/congcong.jpg").convert_alpha()
hotdogImg = pygame.image.load("./img/hotdog.jpg").convert_alpha()
# 背景音乐
pygame.mixer_music.load("./img/game_music.mp3")
pygame.mixer_music.play(loops=0, start=0.0)
# 成绩显示
count = 0
font = pygame.font.SysFont("arial", 40)
score = font.render("score %d" % count, True, (255, 255, 255))
status = font.render("Gaming", True, (255, 255, 255))
# 得到聪聪图片的宽度和高度
w_width = congImg.get_width() - 5
w_height = congImg.get_height() - 5
# 得到热狗图片的宽度和高度
y_width = hotdogImg.get_width() - 5
y_height = hotdogImg.get_height() - 5
fpsClock = pygame.time.Clock() # 创建一个新的Clock对象,可以用来跟踪总共的时间
class cong():
def __init__(self):
self.power = 100
# 聪聪的坐标
self.x = random.randint(0, width - w_width)
self.y = random.randint(0, height - w_height)
# 聪聪移动的方法:移动方向均随机 第四条
def move(self , new_x , new_y):
# 判断移动后是否超出边界
if new_x < 0:
self.x = 0 - new_x
elif new_x > width:
# self.x=width-(new_x-width)
self.x = 0
else:
# 不越界则移动聪聪的位置
self.x = new_x
if new_y < 0:
self.y = 0 - new_y
elif new_y > height:
# self.y=height-(new_y-height)
self.y = 0
else:
# 不越界则移动聪聪的位置
self.y = new_y
self.power -= 1 # 聪聪每移动一次,体力消耗1
def eat(self):
self.power += 20 # 聪聪吃掉热狗,乌龟体力增加20
if self.power > 100:
self.power = 100 # 聪聪体力100(上限)
class Hotdog:
def __init__(self):
# 热狗坐标
self.x = random.randint(0, width - y_width)
self.y = random.randint(0, height - y_height)
def move(self):
new_x = self.x + random.choice([-10])
if new_x < 0:
self.x = width
else:
self.x = new_x
congcong = cong() # 生成聪聪
hotdog = [] # 生成10 - 40个热狗
hotdogs = [Hotdog() for i in range(10,40)]
# pygame有一个事件循环,不断检查用户在做什么。事件循环中,如何让循环中断下来(pygame形成的窗口中右边的插号在未定义前是不起作用的)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == KEYDOWN:
# 通过上下左右方向键控制聪聪的动向
if event.key == pygame.K_LEFT:
congcong.move(congcong.x - 10, congcong.y)
if event.key == pygame.K_RIGHT:
congcong.move(congcong.x + 10, congcong.y)
if event.key == pygame.K_UP:
congcong.move(congcong.x, congcong.y - 10)
if event.key == pygame.K_DOWN:
congcong.move(congcong.x, congcong.y + 10)
screen.blit(background, (0, 0)) # 绘制背景图片
screen.blit(score, (500, 20)) # 绘制分数
screen.blit(status, (0, 20)) # 绘制分数
# 绘制热狗
for item in hotdogs:
screen.blit(hotdogImg, (item.x, item.y))
# pygame.time.delay(100)
item.move() # 热狗的移动
screen.blit(congImg, (congcong.x, congcong.y)) # 绘制聪聪
# 判断游戏是否结束:当聪聪体力值为0或者热狗的数量为0游戏结束
if congcong.power < 0:
print("Game Over: Turtle power is 0")
# 显示游戏状态
status = font.render("Game Over: Congcong power is 0", True, (255, 255, 255))
pygame.display.update() # 更新到游戏窗口
time.sleep(1)
sys.exit(0)
elif len(hotdogs) == 0:
status = font.render("Game Over:Hotdog is empty", True, (255, 255, 255))
pygame.display.update() # 更新到游戏窗口
sys.exit(0)
for item in hotdogs:
# 判断聪聪和热狗是否碰撞?
if ((congcong.x < item.x + y_width) and (congcong.x + w_width > item.x)
and (congcong.y < item.y + y_height) and (w_height + congcong.y > item.y)):
hotdogs.remove(item) #热狗被吃掉
# 吃热狗音乐
# eatsound.play()
count = count + 1 # 累加
score = font.render("score %d" % count, True, (255, 255, 255))
# print("吃掉一个热狗")
# print("聪聪最新体力值为 %d" %congcong.power)
pygame.display.update() # 更新到游戏窗口
fpsClock.tick(10) # 通过每帧调用一次fpsClock.tick(10),这个程序就永远不会以超过每秒10帧的速度运行
效果展示:
进阶双人版游戏:
玩家1 : 通过 ↑↓←→ 来控制上下左右
玩家2 : 通过W,A,S,D 来控制上下左右
运行代码如下:
import random
import time
import pygame
import sys
from pygame.locals import *
width = 640
height = 480
pygame.init()
screen = pygame.display.set_mode([width, height])
pygame.display.set_caption('聪聪吃热狗')
# 设置背景
background = pygame.image.load("./img/bg.jpg").convert_alpha()
congImg1 = pygame.image.load("./img/congcong.jpg").convert_alpha()
congImg2 = pygame.image.load("./img/congcong.jpg").convert_alpha()
hotdogImg = pygame.image.load("./img/hotdog.jpg").convert_alpha()
# 背景音乐
pygame.mixer_music.load("./img/game_music.mp3")
pygame.mixer_music.play(loops=0, start=0.0)
# 成绩显示
count1 = 0
count2 = 0
font = pygame.font.SysFont("arial", 40)
score1 = font.render("score %d" % count1, True, (255, 255, 255))
score2 = font.render("score %d" % count2, True, (255, 255, 0))
status = font.render("Gaming", True, (255, 255, 255))
# 得到聪聪图片的宽度和高度
w_width = congImg1.get_width() - 5
w_height = congImg1.get_height() - 5
# 得到热狗图片的宽度和高度
y_width = hotdogImg.get_width() - 5
y_height = hotdogImg.get_height() - 5
fpsClock = pygame.time.Clock() # 创建一个新的Clock对象,可以用来跟踪总共的时间
class cong():
def __init__(self):
self.power = 100
# 聪聪的坐标
self.x = random.randint(0, width - w_width)
self.y = random.randint(0, height - w_height)
# 聪聪移动的方法:移动方向均随机 第四条
def move(self, new_x, new_y):
# 判断移动后是否超出边界
if new_x < 0:
self.x = width
elif new_x > width:
# self.x=width-(new_x-width)
self.x = 0
else:
# 不越界则移动聪聪的位置
self.x = new_x
if new_y < 0:
self.y = height
elif new_y > height:
# self.y=height-(new_y-height)
self.y = 0
else:
# 不越界则移动聪聪的位置
self.y = new_y
self.power -= 1 # 聪聪每移动一次,体力消耗1
def eat(self):
self.power += 20 # 聪聪吃掉热狗,聪聪体力增加20
if self.power > 100:
self.power = 100 # 聪聪体力100(上限)
class Hotdog:
def __init__(self):
# 热狗坐标
self.x = random.randint(0, width - y_width)
self.y = random.randint(0, height - y_height)
def move(self):
new_x = self.x + random.choice([-10])
if new_x < 0:
self.x = width
else:
self.x = new_x
congcong1 = cong() # 生成聪聪
congcong2 = cong()
hotdog = [] # 生成10 - 40个热狗
hotdogs = [Hotdog() for i in range(10 ,40)]
# pygame有一个事件循环,不断检查用户在做什么。事件循环中,如何让循环中断下来(pygame形成的窗口中右边的插号在未定义前是不起作用的)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == KEYDOWN:
# 通过上下左右方向键控制聪聪的动向
if event.key == pygame.K_LEFT:
congcong1.move(congcong1.x - 10, congcong1.y)
if event.key == pygame.K_RIGHT:
congcong1.move(congcong1.x + 10, congcong1.y)
if event.key == pygame.K_UP:
congcong1.move(congcong1.x, congcong1.y - 10)
if event.key == pygame.K_DOWN:
congcong1.move(congcong1.x, congcong1.y + 10)
if event.key == pygame.K_a:
congcong2.move(congcong2.x - 10, congcong2.y)
if event.key == pygame.K_d:
congcong2.move(congcong2.x + 10, congcong2.y)
if event.key == pygame.K_w:
congcong2.move(congcong2.x, congcong2.y - 10)
if event.key == pygame.K_s:
congcong2.move(congcong2.x, congcong2.y + 10)
screen.blit(background, (0, 0)) # 绘制背景图片
screen.blit(score1, (500, 20)) # 绘制分数
screen.blit(score2, (0, 20)) # 绘制分数
# 绘制热狗
for item in hotdogs:
screen.blit(hotdogImg, (item.x, item.y))
# pygame.time.delay(100)
item.move() # 热狗移动
screen.blit(congImg1, (congcong1.x, congcong1.y)) # 绘制聪聪
screen.blit(congImg2, (congcong2.x, congcong2.y)) # 绘制聪聪
# 判断游戏是否结束:当聪聪体力值为0或者热狗的数量为0游戏结束
if congcong1.power < 0 or congcong2.power < 0:
print("Game Over: Turtle power is 0")
# 显示游戏状态
status = font.render("Game Over: Turtle power is 0", True, (255, 255, 255))
pygame.display.update() # 更新到游戏窗口
time.sleep(1)
sys.exit(0)
elif len(hotdogs) == 0:
status = font.render("Game Over: Fish is empty", True, (255, 255, 255))
pygame.display.update() # 更新到游戏窗口
sys.exit(0)
for item in hotdogs:
# 判断热狗和聪聪是否碰撞?
if (((congcong1.x < item.x + y_width) and (congcong1.x + w_width > item.x)
and (congcong1.y < item.y + y_height) and (w_height + congcong1.y > item.y))):
hotdogs.remove(item) # 热狗被吃掉
# 吃热狗音乐
# eatsound.play()
count1 = count1 + 1 # 累加
score1 = font.render("score %d" % count1, True, (255, 255, 255))
if (((congcong2.x < item.x + y_width) and (congcong2.x + w_width > item.x)
and (congcong2.y < item.y + y_height) and (w_height + congcong2.y > item.y))):
hotdogs.remove(item) #热狗被吃掉
# 吃热狗音乐
# eatsound.play()
count2 = count2 + 1 # 累加
score2 = font.render("score %d" % count2, True, (255, 255, 255))
pygame.display.update() # 更新到游戏窗口
fpsClock.tick(10) # 通过每帧调用一次fpsClock.tick(10),这个程序就永远不会以超过每秒10帧的速度运行
实验效果:
2. 按奇偶排序数组
给定一个非负整数数组 A ,返回一个数组,在该数组中 ,A 的所有偶元素之后跟着所有奇元素。
解法一:
实验代码为:
a = input("请输入需要验证的数组 :").split(' ')
li = list(map(int, a))
def isodd(num):
return num % 2 == 0
sorted_num = sorted(li, key=lambda x: 1 if isodd(x) else 0)
print(sorted_num)
运行结果为:
解法二:
代码如下:
a = input("请输入需要验证的数组 :").split(' ')
li = list(map(int, a))
li1 = []
li2 = []
def isodd(num):
if num % 2 == 0:
li1.append(num)
else:
li2.append(num)
print(li1 + li2)
for i in li:
isodd(i)
运行结果如下:
3.电话号码的字母组合
实验代码如下:
class Number(object):
def keyboard(self, digits):
# 创建字母对应的字符列表的字典
dic = {2: ['a', 'b', 'c'],
3: ['d', 'e', 'f'],
4: ['g', 'h', 'i'],
5: ['j', 'k', 'l'],
6: ['m', 'n', 'o'],
7: ['p', 'q', 'r', 's'],
8: ['t', 'u', 'v'],
9: ['w', 'x', 'y', 'z'],
}
# 存储结果的数组
ret_str = []
if len(digits) == 0:
return []
if len(digits) == 1:
return dic[int(digits[0])
result = self.keyboard(digits[1:])
# result是一个数组列表,遍历后字符串操作,加入列表
for r in result:
for j in dic[int(digits[0])]:
ret_str.append(j + r)
return ret_str
if __name__ == '__main__':
m = Number()
print(m.keyboard('45'))
运行结果为: