2020-11-29 周记录(九)

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,院系: 软件工程,课程记录: []
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容