python学习第三周

函数

函数参数

1.关键字参数 - 字典 - 根据参数名来决定如何执行
2.可变参数 - 元祖
3.命名关键字参数,# 参数(a,b, c, , name, age) 前面的可以不给参数名, *后面的必须给参数名
4.(函数参数)

范例:关键字参数(一般用**kwargs)

def say_hello(**kwargs):
    """根据你给的参数做出判断如果给的参数有name和age就执行if里面的内容,如果没有则执行else"""
    if 'name' in kwargs:
        print('你好, %s!' % kwargs['name'])
    if 'age' in kwargs:
        age = int(kwargs['age'])
        if age <= 16:
            print('小屁孩')
        else:
            print('成年人')
    else:
        print('请提供个人信息')

def main():
    say_hello(name='吕海军', age='24')
    param = {'name': '王大锤', 'age': 15, 'tel': 132325526552}
    # 如果希望将一个字典作为关键字参数传入 需要在参数前放两个*
    say_hello(**param)

if __name__ == '__main__':
    main()

范例:可变参数
可以传入任意多个参数

def my_sum(*args):
    # 传入任意多个数求和
    total = 0
    for val in args:
        total += val
    return total


if __name__ == '__main__':
    print(my_sum(2, 20 ,200))

范例:命名关键字参数
参数(a,b, c, *, name, age),*前面的可以不给参数名, *后面的必须给参数名

def main(a, b, c, *, name, age):
    # *不是参数,*后面的参数必须给出参数名才能执行(name=,age=)
    print(a + b + c)
    print(name, ':', age)


if __name__ == '__main__':
    main(1, 2, 3, name='吕海军', age=24)

补充:函数参数
通过向函数中传入函数 可以写出更通用的代码
calc函数中的第二个参数是另一个函数,它代表了一个二元运算
这样calc函数就不需要跟某一种特定的二元运算耦合在一起
所有calc函数变得通用性更强 可以由传入的第二个参数来决定到底做什么

def calc(my_list, op):
    total = my_list[0]
    for index in range(1, len(my_list)):
        total = op(total, my_list[index])
    return total


def sums(x, y):
    return x + y


def main():
    mylist = [3, 11, 25, 39, 18, 29]
    print(calc(mylist, sums))
    # 如果觉得再定义一个函数比较麻烦,可以使用lambda函数,如下所示可以求每个元素相乘的和
    print(calc(mylist, lambda x, y: x * y))


if __name__ == '__main__':
    main()

补充:函数装饰器
用函数装饰器看递归调用求阶乘的执行过程

def record(fn):
    def wrapper(*args, **kwargs):
        print('执行%s函数之前...' % fn.__name__)
        print(args)
        print(kwargs)
        # 此行代码在执行被装饰的函数
        # 在这行代码的前后我们可以附加其他的代码
        #这些代码可以让我们在执行函数时做一些额外的工作
        val = fn(*args, **kwargs)
        print('%s函数执行完成' % fn.__name__)
        print('返回了%d' % val)
        # 返回被装饰的函数的执行结果
        return val
    return wrapper
# 通过装饰器修饰f函数 让f函数在执行过程中可以做更多额外的操作
@record
def f(n):
    if n == 0 or n == 1:
        return 1
    return n * f(n - 1)


if __name__ == '__main__':
    print(f(5))

面向对象

面向对象基础

面向对象是在面向过程的编程方法不能解决越来越复杂的问题的时候产生的, 一切事物皆对象,通过面向对象的方式,将现实世界的事物抽象成对象,现实世界中的关系抽象成类、继承,帮助人们实现对现实世界的抽象与数字建模。通过面向对象的方法,更利于用人理解的方式对复杂系统进行分析、设计与编程。同时,面向对象能有效提高编程的效率,通过封装技术,消息机制可以像搭积木的一样快速开发出一个全新的系统。面向对象是指一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的集合。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

说明: 以上内容来自百度百科

经过一个星期的学习记录一下自己对面向对象的理解
面向对象的三要素:封装,继承,多态
封装就是把实现一个功能的一串代码进行打包,形成一个函数,代码的执行过程不可见,但是可以通过调用封装好的函数来实现操作,封装防止了程序相互依赖性而带来的变动影响。
继承就像是人和猩猩都是灵长目动物,都有灵长目动物的一切属性,是人或者是猩猩就一定是灵长目,人和猩猩对于灵长目来说就是继承,
多态就是人和猩猩都是灵长目但是又不相同,各有各的特点,不同点就是多态

类和对象

具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象,类实际上就是一种数据类型。
类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。
类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。

类之间的关系

简单的说,类和类之间的关系有三种:is-a、has-a和use-a关系。

is-a关系也叫继承或泛化,比如学生和人的关系、手机和电子产品的关系都属于继承关系。
has-a关系通常称之为关联,比如部门和员工的关系,汽车和引擎的关系都属于关联关系;关联关系如果是整体和部分的关联,那么我们称之为聚合关系;如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时同在也同时消亡),那么这种就是最强的关联关系,我们称之为合成关系。
use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。

@property装饰器

范例:点和线段
点和线段是has-a关系,线段是有无数个点构成,它们是强关联关系,整体和部分的关系
Python中属性和方法访问权限的问题:虽然不建议将属性设置为私有,但是如果直接将属性暴露给外界也是有问题的,比如我们没有办法检查赋给属性的值是否有效。建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。

from math import sqrt

class Point(object):
    def __init__(self, x=0, y=0):
        self._x = x
        self._y = y

    # getter - 访问器
    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

    def move_to(self, x, y):
        self._x = x
        self._y = y

    def move_by(self, dx, dy):
        self._x += dx
        self._y = dy

    def distance_to(self, other):
        dx = self._x - other._x
        dy = self._y - other._y
        return sqrt(dx ** 2 + dy ** 2)


class Line(object):
    def __init__(self, start, end):
        self._start = start
        self._end = end


    @property
    def length(self):
        return self._start.distance_to(self._end)


# 线段上有两个点 - has-a - 关联
# 奥特曼打了小怪兽 - use-a - 依赖
# 学生是人 - is-a - 继承
def main():
    p1 = Point(3, 5)
    p2 = Point()
    line = Line(p1, p2)
    print(line.length)
if __name__ == '__main__':
    main()

范例:用面向对象的思想求三角形的面积,周长
静态方法

from math import sqrt
class Triangle(object):

    def __init__(self, a, b, c):
        self._a = a
        self._b = b
        self._c = c

    # 类方法   
    @classmethod
    def is_valid(cls, a, b, c):
        return a + b > c and b + c > a and a + c > b

    # 静态方法
    # @staticmethod
    # def is_valid(a, b, c):
    #     return a + b > c and b + c > a and a + c > b

    def perimeter(self):
        return self._a +self._b + self._c

    def area(self):
        half = self.perimeter() / 2
        return sqrt(half * (half - self._a) * (half - self._b) * (half - self._c))


def main():
    a = 5
    b = 4
    c = 3
    # 静态方法和类方法都是通过给类发消息来调用的
    if Triangle.is_valid(a, b, c):
        t = Triangle(a, b, c)
        # 可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数
        print(Triangle.perimeter(t))
        print(t.perimeter())
        print((t.area()))
    else:
        print('不能构成三角形')

if __name__ == '__main__':
    main()

抽象类

python没有从语言层面支持抽象类的概念
我们可以通过abc模块来制造抽象类的效果
在定义类的时候通过指定metaclass=ABCMeta可以将声明为抽象类
抽象类似不能创建对象的 抽象类存在的意义是专门拿给其他类继承
abc模块中还有一个包装器abstractmethod
通过这个包装器可以将方法包装为模拟抽象方法 必须要求子类进行重写

范例:使用面向对象计算总经理,程序员,销售员的工资

from abc import ABCMeta, abstractmethod 


class Employee(object, metaclass=ABCMeta):
    """员工"""

    def __init__(self, name):
        """
        初始化方法
        :param name:员工姓名
        """
        self._name = name

    @property
    def name(self):
        return self._name

    # 包装器abstractmethod可以要求子类必须重写get_salary()方法
    @abstractmethod
    def get_salary(self):
        """
        获得月薪
        :return:得到的月薪
        """
        pass


class Manager(Employee):

    def get_salary(self):
        return 15000


class Programmer(Employee):
    """定义程序员类"""

    def __init__(self, name):
        super().__init__(name)
        self._working_hour = 0

    @property
    def working_hour(self):
        return self.working_hour

    # setter - 修改器
    @working_hour.setter
    def working_hour(self,working_hour):
        self._working_hour = working_hour if working_hour > 0 else 0

    def get_salary(self):
        return 150.0 * self._working_hour


class Salesman(Employee):

    def __init__(self, name,sales=0):
        super().__init__(name)
        self._sales = sales

    @property
    def sales(self):
        return self._sales

    @sales.setter
    def sales(self, sales):
        self._sales = sales if sales > 0 else 0

    def get_salary(self):
        return 1200.0 + self._sales * 0.05


def main():

    emps = [Manager('刘备'), Programmer('诸葛亮'), Manager('曹操'), Salesman('赵云'), Programmer('张辽')]

    for emp in emps:
        if isinstance(emp, Programmer):
            emp.working_hour = int(input('请输入%s本月工作时间' % emp.name))
        elif isinstance(emp, Salesman):
            emp.sales = float(input('请输入%s本月销售额' % emp.name))
        # 同样是接收get_salary这个消息 但是不同的员工表现出了不同的行为
        # 因为三个子类都重写了get_salary方法 所有这个方法会表现出多态行为
        print('%s本月工资为: ¥%.2f元' % (emp.name, emp.get_salary()))

if __name__ == '__main__':
    main()

用pygame“写”的小游戏
五子棋

"""五子棋"""
import pygame
EMPTY = 0
BLACK = 1
WHITE = 2
black_color = [0, 0, 0]
white_color = [255, 255, 255]


class Renjuboard(object):

    def __init__(self):
        self._board = [[]] * 15
        self.reset()

    def reset(self):
        for row in range(len(self._board)):
            self._board[row] = [EMPTY] * 15

    def move(self, row, col, is_black):
        if self._board[row][col] == EMPTY:
            self._board[row][col] = BLACK if is_black else WHITE
            return True
        return False



    def draw(self, screen):
        for x in range(1, 16):
            pygame.draw.line(screen, black_color, [40, 40 * x], [600, 40 * x], 1)
            pygame.draw.line(screen, black_color, [40 * x, 40], [40 * x, 600], 1)
        pygame.draw.rect(screen, black_color, [36, 36, 568, 568], 4)
        pygame.draw.circle(screen, black_color, [320, 320], 5, 0)
        pygame.draw.circle(screen, black_color, [160, 160], 5, 0)
        pygame.draw.circle(screen, black_color, [480, 480], 5, 0)
        pygame.draw.circle(screen, black_color, [480, 160], 5, 0)
        pygame.draw.circle(screen, black_color, [160, 480], 5, 0)
        for row in range(len(self._board)):
            for col in range(len(self._board[row])):
                if self._board[row][col] != EMPTY:
                    ccolor = black_color \
                        if self._board[row][col] == BLACK else white_color
                    pos = [40 * (col + 1), 40 * (row + 1)]
                    pygame.draw.circle(screen, ccolor, pos, 20, 0)
        pygame.display.flip()


def main():
    board = Renjuboard()
    is_black = True
    pygame.init()
    pygame.display.set_caption('五子棋')
    screen = pygame.display.set_mode([640, 640])
    screen.fill([255, 255, 0])
    board.draw(screen)
    pygame.display.flip()
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYUP:
                pass
            elif event.type == pygame.MOUSEBUTTONDOWN\
                    and event.button == 1:
                x, y = event.pos
                if 40 <= x <= 600 and 40 <= y <= 600:
                    row = round((y - 40) / 40)
                    col = round((x - 40) / 40)
                    if board.move(row, col, is_black):
                        is_black = not is_black
                        screen.fill([255, 255, 0])
                        board.draw(screen)
                        pygame.display.flip()
    pygame.quit()



if __name__ == '__main__':
    main()

大球吃小球(有bug)
点击鼠标生成小球

"""大球吃小球"""
from math import sqrt
from random import randint
import pygame


class Ball(object):
    def __init__(self, center, color, radius, sx, sy):
        """
        小球类初始化
        :param center: 小球中心点(x, y)坐标
        :param color: 小球的颜色
        :param radius: 小球的半径
        :param sx: 小球横向移动的速度
        :param sy: 小球纵向移动的速度
        """
        self._center = center
        self._color = color
        self._radius = radius
        self._sx = sx
        self._sy = sy

    def move(self):
        x, y = self._center[0], self._center[1]
        x += self._sx
        y += self._sy
        self._center = (x, y)
        if x + self._radius >= 800 or x - self._radius <= 0:
            self._sx = -self._sx
        if y + self._radius >= 600 or y - self._radius <= 0:
            self._sy = -self._sy

    def eat(self, other):
        x1 = self._center[0]
        y1 = self._center[1]
        x2 = other._center[0]
        y2 = other._center[1]
        if sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) < self._radius + other._radius:
            if self._radius > other._radius:
                self._radius += 2
                other._radius = 0
            elif self._radius < other._radius:
                self._radius = 0
                other._radius += 2

    def draw(self, screen):
        pygame.draw.circle(screen, self._color, self._center, self._radius, 0)


def main():
    balls = []
    pygame.init()
    screen = pygame.display.set_mode((800, 600))

    red_color = (255, 0, 0)
    # ball = Ball((100, 100), red_color, 30, 3, 3)
    pygame.display.set_caption('大球吃小球')
    clock = pygame.time.Clock()
    running = True
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                color = random_color()
                radius = randint(10, 20)
                sx, sy = randint(-10, 10), randint(-10, 10)
                center = event.pos
                ball = Ball(center, color, radius, sx, sy)
                balls.append(ball)
        refrsh(screen, balls)
        clock.tick(30)

        for ball in balls:
            ball.move()
            if ball._radius == 0:
                balls.remove(ball)
            for ball1 in balls:
                ball.eat(ball1)
    pygame.quit()


def refrsh(screen, balls):
    bg_color = (202, 202, 202)
    screen.fill(bg_color)
    for ball in balls:
        ball.draw(screen)
    pygame.display.flip()


def random_color():
    red = randint(0, 255)
    green = randint(0, 255)
    blue = randint(0, 255)
    return red, green, blue

if __name__ == '__main__':
    main()

贪吃蛇:wasd控制方向

from abc import ABCMeta, abstractmethod
from random import randint
import pygame

BLACK_COLOR = (0, 0, 0)
FOOD_COLOR = (255, 50, 50)
GREEN_COLOR = (0, 255, 0)
UP = 0
RIGHT = 1
DOWN = 2
LEFT = 3


class GameObject(object, metaclass=ABCMeta):

    def __init__(self, x=0, y=0, color=BLACK_COLOR):
        self._x = x
        self._y = y
        self._color = color

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

    @abstractmethod
    def draw(self, screen):
        pass


class Wall(GameObject):

    def __init__(self, x, y, width, height, color=BLACK_COLOR):
        super().__init__(x, y, color)
        self._width = width
        self._height = height

    @property
    def width(self):
        return self._width

    @property
    def hight(self):
        return self._height

    def draw(self, screen):
        pygame.draw.rect(screen, self._color, (self._x, self._y, self._width, self._height), 4)


class SnackNode(GameObject):

    def __init__(self, x, y, size, color=GREEN_COLOR):
        super().__init__(x, y, color)
        self._size = size

    @property
    def size(self):
        return self._size

    def draw(self, screen):
        pygame.draw.rect(screen, self._color, (self._x, self._y, self._size, self._size), 0)
        pygame.draw.rect(screen, BLACK_COLOR, (self._x, self._y, self._size, self._size), 1)


class Food(GameObject):

    def __init__(self, x, y, size, color=FOOD_COLOR):
        super().__init__(x, y, color)
        self._size = size
        self._hidden = False

    def draw(self, screen):
        if not self._hidden:
            pygame.draw.circle(screen, self._color, (self._x + self._size // 2, self._y + self._size // 2),
                               self._size // 2, 0)
        self._hidden = not self._hidden


class Snake(GameObject):

    def __init__(self):
        super().__init__()
        self._dir = LEFT
        self._nodes = []
        self._alive = True
        self._eat_food = False
        for index in range(5):
            node = SnackNode(290 + index * 20, 250, 20)
            self._nodes.append(node)

    @property
    def dir(self):
        return self._dir

    @property
    def head(self):
        return self._nodes[0]

    @property
    def alive(self):
        return self._alive

    def change_dir(self, new_dir):
        if new_dir != self._dir and (self._dir + new_dir) % 2 != 0:
            self._dir = new_dir

    def draw(self, screen):
        for node in self._nodes:
            node.draw(screen)

    def move(self):
        head = self.head
        snake_dir = self._dir
        x, y, size = head.x, head.y, head.size
        if snake_dir == UP:
            y -= size
        elif snake_dir == RIGHT:
            x += size
        elif snake_dir == DOWN:
            y += size
        else:
            x -= size
        new_head = SnackNode(x, y, size)
        self._nodes.insert(0, new_head)
        self._nodes.pop()

    def collide(self, wall):
        """判断是否撞墙"""
        head = self.head
        # 判断顺序是左, 右, 上, 下
        if head.x < wall.x or head.x + head.size > wall.x + wall.width or\
                    head.y < wall.y or head.y + head.size > wall.y + wall.hight:
            self._alive = False

    def eat_food(self, food):
        if self.head.x == food.x and self.head.y == food.y:
            tail = self._nodes[-1]
            self._nodes.append(tail)
            return True
        return False

    def eat_me(self):
        head = self.head
        new_nodes = self._nodes[4:]
        for sb in new_nodes:
            if head.x == sb.x and head.y == sb.y:
                self._alive = False


def main():

    def refresh():
        """刷新游戏窗口"""
        screen.fill((242, 242, 242))
        wall.draw(screen)
        food.draw(screen)
        snake.draw(screen)
        pygame.display.flip()

    def handle_key_event(key_event):
        """处理按键事件"""
        key = key_event.key
        if key == pygame.K_F2:
            reset_game()
        else:
            if snake.alive:
                new_dir = snake.dir
                if key == pygame.K_w:
                    new_dir = UP
                elif key == pygame.K_d:
                    new_dir = RIGHT
                elif key == pygame.K_s:
                    new_dir = DOWN
                elif key == pygame.K_a:
                    new_dir = LEFT
                if new_dir != snake.dir:
                    snake.change_dir(new_dir)

    def create_food():
        row = randint(1, 28)
        col = randint(1, 28)
        return Food(10 + 20 * col, 10 + 20 * row, 20)

    def reset_game():
        nonlocal food, snake
        food = create_food()
        snake = Snake()

    # 设置
    wall = Wall(10, 10, 600, 600)
    food = create_food()
    snake = Snake()
    pygame.init()
    screen = pygame.display.set_mode((620, 620))
    pygame.display.set_caption('贪吃蛇')
    # 给屏幕填充颜色,(
    screen.fill((242, 242, 242))
    # 窗口刷新
    pygame.display.flip()
    # 创建时钟,设置帧数
    clock = pygame.time.Clock()
    running = True
    # 循环接收事件,
    while running:
        for event in pygame.event.get():
            # 如果点了 关闭 结束循环
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                handle_key_event(event)
        if snake.alive:
            refresh()
        # 帧数20帧
        clock.tick(5)
        if snake.alive:
            snake.move()
            snake.eat_me()
            snake.collide(wall)
            if snake.eat_food(food):
                food = create_food()

    pygame.quit()


if __name__ == '__main__':
    main()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值