Pygame
重构:模块 game_functions
game_functions.py--->函数 check_events()
import sys
import pygame
def check_events():
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
game_functions.py--->函数 update_screen()
import sys
import pygame
def check_events():
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
def update_screen(ai_settings,screen,ship):
"""更新屏幕上的图像,并切换到新屏幕"""
#每次循环都重新绘制屏幕
screen.fill(ai_settings.bg_color)
ship.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
修改alien_invasion.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#创建一艘飞船
ship = Ship(screen)
#开始游戏的主循环
while True:
gf.check_events()
gf.update_screen(ai_settings,screen,ship)
run_game()
左右移动飞船
game_functions.py
import sys
import pygame
def check_events(ship):
"""响应按键和鼠标事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def update_screen(ai_settings,screen,ship):
"""更新屏幕上的图像,并切换到新屏幕"""
#每次循环都重新绘制屏幕
screen.fill(ai_settings.bg_color)
ship.blitme()
#让最近绘制的屏幕可见
pygame.display.flip()
ship.py
import pygame
class Ship():
def __init__(self,screen):
"""初始化飞船并设置其初始位置"""
self.screen = screen
#加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp') #加载图像
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
#将梅艘新飞船放在屏幕底部中央
self.rect.centerx = self.screen_rect.centerx #飞船中心的x坐标
self.rect.bottom = self.screen_rect.bottom #飞船下边缘的y坐标
#移动标志
self.moving_right = False
self.moving_left = False
def update(self):
"""根据移动标志调整飞船的位置"""
if self.moving_right:
self.rect.centerx += 1
if self.moving_left:
self.rect.centerx -= 1
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
alien_invasion.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#创建一艘飞船
ship = Ship(screen)
#开始游戏的主循环
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings,screen,ship)
run_game()
调整飞船的速度
settings.py
class Settings():
"""储存《外星人入侵》的所有设置的类"""
def __init__(self):
"""初始化游戏的设置"""
#屏幕设置
self.screen_width = 1280
self.screen_height = 800
self.bg_color = (230,230,230)
#飞船的设置
self.ship_speed_factor = 1.5
ship.py
import pygame
class Ship():
def __init__(self,ai_settings,screen):
"""初始化飞船并设置其初始位置"""
self.screen = screen
self.ai_settings = ai_settings
#加载飞船图像并获取其外接矩形
self.image = pygame.image.load('images/ship.bmp') #加载图像
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
#将梅艘新飞船放在屏幕底部中央
self.rect.centerx = self.screen_rect.centerx #飞船中心的x坐标
self.rect.bottom = self.screen_rect.bottom #飞船下边缘的y坐标
#在飞船的属性center中储存小数值
self.center = float(self.rect.centerx)
#移动标志
self.moving_right = False
self.moving_left = False
def update(self):
"""根据移动标志调整飞船的位置"""
#更新飞船的center值,而不是rect
if self.moving_right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left:
self.center -= self.ai_settings.ship_speed_factor
#根据self.center更新rect对象
self.rect.centerx = self.center
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
alien_invasion.py
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
#初始化游戏并创建一个屏幕对象
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode(
(ai_settings.screen_width,ai_settings.screen_height))
pygame.display.set_caption("Alien Invasion")
#创建一艘飞船
ship = Ship(ai_settings,screen)
#开始游戏的主循环
while True:
gf.check_events(ship)
ship.update()
gf.update_screen(ai_settings,screen,ship)
run_game()
Python 常见双下划线关键字的用法
1.__init__
__init__ 方法通常用在初始化一个类实例的时候,例如:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
2.__str__
__str__用来返回对象的字符串表达式。例如:
class Person(object):
def __init__(self, name):
super(Person, self).__init__()
self.name = name
def __str__(self):
return'Hola,%s' % self.name
lina = Person('Lina')
print(lina)
在我们编写一个新的Python类的时候,总是在最开始位置写一个初始化方法__init__,以便初始化对象,然后会写一个__str__方法,方面我们调试程序。
3.__new__
__new__方法的调用是发生在__init__之前的
class Person(object):
def __new__(cls,*args, **kwargs):
print('new called')
return object.__new__(cls)
def __init__(self, name):
print('init called')
super(Person, self).__init__()
self.name = name
def __str__(self):
return'Hola,%s' % self.name
lina = Person('Lina')
print(lina)
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__ 和 __new__ 最主要的区别在于:
1.__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
2.__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。
__new__ 的作用
依照Python官方文档的说法,__new__方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass。
4.__name__和__main__
为了区分 主执行代码和被调用文件,python引入了变量:__name__。__name__就是标识模块的名字的一个系统变量。这里分两种情况:假如当前模块是主模块(也就是调用其他模块的模块),那么此模块名字就是__main__,通过if判断这样就可以执行“__mian__:”后面的主函数内容;假如此模块是被import的,则此模块名字为文件名字(不加后面的.py),通过if判断这样就会跳过“__mian__:”后面的内容。
5.__slots__
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class实例能添加的属性。比如,只允许对Student实例添加name和age属性:
class Student(object):
slots = ('name', 'age') # 用tuple定义允许绑定的属性名称
Python __str__() 方法
定义 __str__() 方法:
class Cat:
"""定义一个猫类"""
def __init__(self, new_name, new_age):
"""在创建完对象之后 会自动调用, 它完成对象的初始化的功能"""
# self.name = "汤姆"
# self.age = 20
self.name = new_name
self.age = new_age # 它是一个对象中的属性,在对象中存储,即只要这个对象还存在,那么这个变量就可以使用
# num = 100 # 它是一个局部变量,当这个函数执行完之后,这个变量的空间就没有了,因此其他方法不能使用这个变量
def __str__(self):
"""返回一个对象的描述信息"""
# print(num)
return "名字是:%s , 年龄是:%d" % (self.name, self.age)
def eat(self):
print("%s在吃鱼...." % self.name)
def drink(self):
print("%s在喝可乐..." % self.name)
def introduce(self):
# print("名字是:%s, 年龄是:%d" % (汤姆的名字, 汤姆的年龄))
# print("名字是:%s, 年龄是:%d" % (tom.name, tom.age))
print("名字是:%s, 年龄是:%d" % (self.name, self.age))
# 创建了一个对象
tom = Cat("汤姆", 30)
print(tom)
总结:
1.在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法
2.当使用print输出对象的时候,只要自己定义了__str__(self)方法,那么就会打印从在这个方法中return的数据
3.__str__方法需要返回一个字符串,当做这个对象的描写
Python学校人事管理系统
编写类
import datetime
class PersonTypeError(TypeError):
pass
class PersonValueError(ValueError):
pass
class Person():
_num = 0
def __init__(self,name,sex,birthday,ident):
if not (isinstance(name,str) and sex in ("女","男")):
raise PersonValueError(name,sex)
try:
birth = datetime.date(*birthday) #生成一个日期对象
except:
raise PensonValueError("Wrong date:",birthday)
self._name = name
self._sex = sex
self._birthday = birth
self._id = ident
Person._num += 1 #实例计数、
def id(self):
return self._id
def name(self):
return self._name
def sex(self):
return self._sex
def birthday(self):
return self._birthday
def age(self):
return (datetime.date.today().year - self._birthday.year)
def set_name(self,name):
"""修改名字"""
if not isinstance(name,str):
raise PersonValueError("set_name",name)
self._name = name
def __lt__(self,another):
if not isinstance(another,Person):
raise PersonTypeError(another)
return self._id < another._id
@classmethod
def num(cls): return Person._num
def __str__(self):
return " ".join((self._id,self._name,self._sex,str(self._birthday)))
def details(self):
return ",".join(("编号: " + self._id,
"姓名: " + self._name,
"性别: " + self._sex,
"出生日期: " + str(self._birthday)))
class Student(Person):
_id_num = 0
@classmethod
def _id_gen(cls):
"""实现学号生成规则"""
cls._id_num += 1
year = datetime.date.today().year
return "1{:04}{:05}".format(year,cls._id_num)
def __init__(self,name,sex,birthday,department):
Person.__init__(self,name,sex,birthday,Student._id_gen())
self._department = department
self._enroll_date = datetime.date.today()
self._courses = {} #一个空字典
def set_course(self,course_name):
"""设置字典键对应值为空"""
self._courses[course_name] = None
def set_score(self,course_name,score):
"""给字典中的键赋值"""
if course_name not in self._courses:
raise PersonValueError("No this course selected:",course_name)
self._courses[course_name] = score
def scores(self):
return [(cname,self._courses[cname]) for cname in self._courses]
def details(self):
return ",".join((Person.details(self),
"入学日期: " + str(self._enroll_date),
"院系: " + self._department,
"课程记录: " + str(self.scores())))
class Staff(Person):
_id_num = 0
@classmethod
def _id_gen(cls,birthday):
"""实现职工号生成规则"""
cls._id_num += 1
birth_year = datetime.date(*birthday).year
return "0{:04}{:05}".format(birth_year,cls._id_num)
def __init__(self,name,sex,birthday,entry_date=None):
super().__init__(name,sex,birthday,Staff._id_gen(birthday))
if entry_date:
try:
self._entry_date = datetime.date(*entry_date)
except:
raise PersonValueError("Wrong date:",entry_date)
else:
self._entry_date = datetime.date.today()
self._salary = 1720 #工资,可修改
self._department = "未定" #需另行设定
self._position = "未定" #需另行设定
def set_salary(self,amount):
if not type(amount) is int:
raise TypeError
self._salary = amount
def set_position(self,position):
self._position = position
def set_department(self,department):
self._department = department
def details(self):
return ",".join((super().details(),
"入职日期: " + str(self._entry_date),
"院系: " + self._department,
"职位: " + self._position,
"工资: " + str(self._salary)))
调用
p1 = Staff("谢雨洁","女",(1995,7,30),(2002,5,5))
p2 = Staff("克拉克","男",(1990,6,21))
p3 = Student("王晓豪","男",(1999,11,12),"计算机科学与技术")
p4 = Student("布鲁斯","男",(1997,10,29),"软件工程")
print(p1)
print(p2)
print(p3)
print(p4)
p1.set_department("数学")
p1.set_position("副教授")
p1.set_salary(8400)
print(p1.details())
print(p2.details())
p3.set_course("数据结构")
p3.set_score("数据结构",100)
p3.set_course("算法")
p3.set_score("算法",99)
print(p3.details())
print(p4.details())
结果
0199500001 谢雨洁 女 1995-07-30
0199000002 克拉克 男 1990-06-21
1202000001 王晓豪 男 1999-11-12
1202000002 布鲁斯 男 1997-10-29
编号: 0199500001,姓名: 谢雨洁,性别: 女,出生日期: 1995-07-30,入职日期: 2002-05-05,院系: 数学,职位: 副教授,工资: 8400
编号: 0199000002,姓名: 克拉克,性别: 男,出生日期: 1990-06-21,入职日期: 2020-11-30,院系: 未定,职位: 未定,工资: 1720
编号: 1202000001,姓名: 王晓豪,性别: 男,出生日期: 1999-11-12,入学日期: 2020-11-30,院系: 计算机科学与技术,课程记录: [('数据结构', 100), ('算法', 99)]
编号: 1202000002,姓名: 布鲁斯,性别: 男,出生日期: 1997-10-29,入学日期: 2020-11-30,院系: 软件工程,课程记录: []