Python_week03
2018-03-17 15:37
134 查看
函数
我们在构建函数的时候会发现很多函数几乎完全相同,那么懒惰的程序员怎么能容忍这种事呢,如下面:mylist = [1, 3, 4, 7] def sum1(mylist): """计算列表元素之和""" total = mylist[0] for index in range(1,len(mylist)): total += mylist[index] return total print(sum1(mylist)) def pro(mylist): """计算列表元素之积""" total = mylist[0] for index in range(1,len(mylist)): total *= mylist[index] return total print(pro(mylist)
可以看出上面两个函数除了运算符号不同 其他代码完全一样,那么我们有没有办法可以一个函数搞定呢?当然可以啦!如下:
def calc(my_list, op): """对列表中的元素做运算""" total = my_list[0] for index in range(1, len(my_list)): total = op(total, my_list[index]) # op可以换成add 或者 mul return total def add(x, y): return x + y def mul(x, y): return x * y print(calc(my_list, add) print(calc(my_list, mul)
mylist = [1, 3, 4, 7] def calc(my_lis 4000 t, op): """对列表中的元素做运算""" total = mylist[0] for index in range(1, len(mylist)): total = op(total, mylist[index]) # op可以换成add 或者 mul return total def add(x, y): return x + y def mul(x, y): return x * y print(calc(mylist, add)) print(calc(mylist, mul)) #如果觉得还要定义加法,乘法麻烦的话 还可以使用lambda函数(匿名函数) print(calc(mylist, lambda x, y: x + y)
@property装饰器
之前我们讨论过Python中属性和方法访问权限的问题,虽然我们不建议将属性设置为私有的,但是如果直接将属性暴露给外界也是有问题的,比如我们没有办法检查赋给属性的值是否有效。我们之前的建议是将属性命名以单下划线开头,通过这种方式来暗示属性是受保护的,不建议外界直接访问,那么如果想访问属性可以通过属性的getter(访问器)和setter(修改器)方法进行对应的操作。如果要做到这点,就可以考虑使用@property包装器来包装getter和setter方法,使得对属性的访问既安全又方便,代码如下所示。class Person(object): def __init__(self, name, age): self._name = name self._age = age # 访问器 - getter方法 @property def name(self): return self._name # 访问器 - getter方法 @property def age(self): return self._age # 修改器 - setter方法 @age.setter def age(self, age): self._age = age def play(self): if self._age <= 16: print('%s正在玩飞行棋.' % self._name) else: print('%s正在玩斗地主.' % self._name) def main(): person = Person('王大锤', 12) person.play() person.age = 22 person.play() # person.name = '白元芳' # AttributeError: can't set attribute 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 @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, b, c = 3, 4, 5 # 静态方法和类方法都是通过给类发消息来调用的 if Triangle.is_valid(a, b, c): t = Triangle(a, b, c) print(t.perimeter()) # 也可以通过给类发消息来调用对象方法但是要传入接收消息的对象作为参数 # print(Triangle.perimeter(t)) print(t.area()) # print(Triangle.area(t)) else: print('无法构成三角形.') if __name__ == '__main__': main()
和静态方法比较类似,Python还可以在类中定义类方法,类方法的第一个参数约定名为cls,它代表的是当前类相关的信息的对象(类本身也是一个对象,有的地方也称之为类的元数据对象),通过这个参数我们可以获取和类相关的信息并且可以创建出类的对象,代码如下所示。
from time import time, localtime, sleep class Clock(object): """数字时钟""" def __init__(self, hour=0, minute=0, second=0): self._hour = hour self._minute = minute self._second = second @classmethod def now(cls): ctime = localtime(time()) return cls(ctime.tm_hour, ctime.tm_min, ctime.tm_sec) def run(self): """走字""" self._second += 1 if self._second == 60: self._second = 0 self._minute += 1 if self._minute == 60: self._minute = 0 self._hour += 1 if self._hour == 24: self._hour = 0 def show(self): """显示时间""" return '%02d:%02d:%02d' % \ (self._hour, self._minute, self._second) def main(): # 通过类方法创建对象并获取系统时间 clock = Clock.now() while True: print(clock.show()) sleep(1) clock.run() if __name__ == '__main__': main()
类之间的关系
is-a关系也叫继承或泛化,比如学生和人的关系、手机和电子产品的关系都属于继承关系。has-a关系通常称之为关联,比如部门和员工的关系,汽车和引擎的关系都属于关联关系;关联关系如果是整体和部分的关联,那么我们称之为聚合关系;如果整体进一步负责了部分的生命周期(整体和部分是不可分割的,同时同在也同时消亡),那么这种就是最强的关联关系,我们称之为合成关系。
use-a关系通常称之为依赖,比如司机有一个驾驶的行为(方法),其中(的参数)使用到了汽车,那么司机和汽车的关系就是依赖关系。
继承和多态
其实我们可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则。下面我们先看一个继承的例子。class Person(object): """人""" def __init__(self, name, age): self._name = name self._age = age @property def name(self): return self._name @property def age(self): return self._age @age.setter def age(self, age): self._age = age def play(self): print('%s正在愉快的玩耍.' % self._name) def watch_av(self): if self._age >= 18: print('%s正在观看爱情动作片.' % self._name) else: print('%s只能观看《熊出没》.' % self._name) class Student(Person): """学生""" def __init__(self, name, age, grade): super().__init__(name, age) self._grade = grade @property def grade(self): return self._grade @grade.setter def grade(self, grade): self._grade = grade def study(self, course): print('%s的%s正在学习%s.' % (self._grade, self._name, course)) class Teacher(Person): """老师""" def __init__(self, name, age, title): super().__init__(name, age) self._title = title @property def title(self): return self._title @title.setter def title(self, title): self._title = title def teach(self, course): print('%s%s正在讲%s.' % (self._name, self._title, course)) def main(): stu = Student('王大锤', 15, '初三') stu.study('数学') stu.watch_av() t = Teacher('老王', 40, '老叫兽') t.teach('Python程序设计') t.watch_av() if __name__ == '__main__': main()
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。
# Python没有从语言层面支持抽象类的概念 # 我们可以通过abc模块拉制造抽象类的效果 # 在定义类的时候通过制定metaclass=ABCMeta 可以将类声明为抽象类 # 在抽象类是不能创建对象的 抽象类存在的意义是专门拿给其他类继承 # abc模块中还有一个包装器abstractmethod # 通过这个包装器可以将方法包装为抽象方法 必须要求子类进行重写 from abc import ABCMeta, abstractmethod class Staff(object): def __init__(self, name): self._name = name @property def name(self): return self._name @abstractmethod def get_salary(self): pass class Manager(Staff): def __init__(self, name): super().__init__(name) def get_salary(self): return 15000 class Programer(Staff): def __init__(self, name, working_hour): super().__init__(name) self._working_hour = working_hour @property def working_hour(self): return self._working_hour @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 self._working_hour * 150 class Saler(Staff): def __init__(self, name, sales): super().__init__(name) self._sales = sales @property def percentage(self): return self._sales def get_salary(self): return 1200 + self._sales * 0.05 def main(): m = Manager('老王') p = Programer('小黑', 120) s = Saler('小红', 5000) x = [m, p, s] y = {} for staff in x: if isinstance(staff, Programer): staff.working_hour = int(input()) # 同样是接收get_salary这个消息 但是不同的员工变现出了不同的行为 # 因为三个子类都重写了get_salary方法 所以这个方法会变现出多态行为 y[staff.name] = staff.get_salary() print(y) if __name__ == '__main__': main()
综合案例
贪吃蛇
通过pycharm实现吃蛋,长大,撞壁,碰撞自身结束游戏的功能from abc import ABCMeta, abstractmethod from random import randint import pygame BLACK = (0, 0, 0) FOOD_COLOR = (252, 168, 150) GRENN_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): self._x = x self._y = y self._color = color @abstractmethod def draw(self, screen): pass @property def x(self): return self._x @property def y(self): return self._y class Wall(GameObject): """围墙类""" def __init__(self, x, y, width, height, color=BLACK): super().__init__(x, y, color) self._width = width self._height = height self._color = color def draw(self, screen): pygame.draw.rect(screen, self._color, (self._x, self._y, self._width, self._height), 4) @property def width(self): return self._width @property def height(self): return self._height class Food(GameObject): """食物类""" def __init__(self, x, y, size, color=FOOD_COLOR): super().__init__(x, y, color) self._size = size self._color = color 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 SnakeNode(GameObject): """蛇节点类""" def __init__(self, x, y, size, color=GRENN_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, (self._x, self._y, self._size, self._size), 1) class Snake(GameObject): """蛇类""" def __init__(self): super().__init__() self._dir = LEFT self._nodes = [] self._has_eat_food = False for index in range(5): node = SnakeNode(290 + index * 20, 250, 20) self._nodes.append(node) @property def dir(self): return self._dir def draw(self, screen): for node in self._nodes: node.draw(screen) def change_dir(self, new_dir): # 改变方向的方法,不能反方向移动 if new_dir != self.dir and (self._dir + new_dir) % 2 != 0: self._dir = new_dir def move(self): # 移动的方法 head = self._nodes[0] 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 = SnakeNode(x, y, size) self._nodes.insert(0, new_head) if self._has_eat_food: # 吃到食物就不会去掉最后一节 self._has_eat_food = False else: # 没吃到食物就会都头部增加一节,尾部减少一节 self._nodes.pop() def collide(self, wall): # 通过判断头部的坐标与墙的坐标是否重合判断是否撞墙 head = self._nodes[0] return 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.height def eat_food(self,food): if self._nodes[0].x == food.x and self._nodes[0].y == food.y: self._has_eat_food = True return True def body(self): # 通过对蛇的每个节点位置的遍历判断是否和头部重叠 for node in self._nodes[4:]: if self._nodes[0].x == node.x and self._nodes[0].y == node.y: return True 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() elif key in (pygame.K_w, pygame.K_d, pygame.K_s, pygame.K_a): # 游戏中只有w a s d方向键有效, 其他键不做反馈 if not game_over: 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 snake.change_dir(new_dir) def creat_egg(): row = randint(0, 29) col = randint(0, 29) return Food(10 + 20 * row, 10 + 20 * col, 20) def reset_game(): nonlocal food, snake, game_over food = creat_egg() snake = Snake() pygame.event.clear() game_over = False def score(): """窗口上显示计分""" fontbjecet = pygame.font.SysFont('SimHei', 32) WenBenKuangDuiXiang = fontbjecet.render('score: %d' % food_count, True, [0, 0, 0]) KuangDuiXiang = WenBenKuangDuiXiang.get_rect() KuangDuiXiang.center = (510, 25) screen.blit(WenBenKuangDuiXiang, KuangDuiXiang) pygame.display.update() pygame.init() screen = pygame.display.set_mode((620, 620)) # 设置窗口大小 pygame.display.set_caption('贪吃蛇') # 设置窗口标题 screen.fill((242, 242, 242)) # 填充窗口底色 wall = Wall(10, 10, 600, 600) snake = Snake() food = creat_egg() pygame.display.flip() # 刷新窗口 clock = pygame.time.Clock() # 导入窗口刷新帧数 game_over = False running = True food_count = 0 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 not game_over: refresh() snake.move() snake.eat_food(food) if snake.collide(wall) or snake.body(): game_over = True if snake.eat_food(food): food = creat_egg() food_count += 10 score() clock.tick(10) pygame.quit() if __name__ == '__main__': main()
文件读写
文件是存在硬盘上的,我们需要给系统发送指令,才能再读写文件。在Python中我们使用内置函数open(),操作代码如下:import time # 异常机制 - 处理程序在运行过程中出现的意外状况的手段 # 因为不是所有的问题都能够在程序调试程序的时候就能发现 # 打开文件 --> 判断大小 --> 分配内存 --> 读取文件 --> 关闭文件 def main(): try: # ./表示在当前路径下 ../表示上一级路径 with open('../abc/hello.txt', 'r', encoding='utf-8') as fs: content = fs.readlines() # 读整个文件 for line in content: # 一行一行的读文件 print(line, end='') time.sleep(1) #print(content) #mylist = fs.readlines() # 将文件读进一个列表容器 #print(mylist) except FileNotFoundError as e: # 把错误做别名处理 print(e) # 把错误信息打印出来 print('指定的文件无法打开.') except IOError: print('读写文件是出现错误.') print('程序执行结束') if __name__ == '__main__': main()
def main(): try: with open('../abc/picture.jpg', 'rb') as fs1: # 读文件 data = fs1.read() print(data) print(type(data)) with open('../efg/view.jpg', 'wb') as fs2: # 将读取的内容写到另一个文件中 fs2.write(data) except FileNotFoundError as e: # 把错误做别名处理 print(e) # 把错误信息打印出来 print('指定的文件无法打开.') except IOError: print('读写文件是出现错误.') print('程序执行结束') if __name__ == '__main__': main()
当我们在文件读写的过程中就会发现,比如字符串,列表,字典等数据类型在某些程序中是无法识别的,那么为了解决这个问题引入json,就可以在相互传递数据了。
以下代码是在API接口扒取数据。
import requests import json def main(): # request / response resp = requests.get('http://api.tianapi.com/meinv/?key=e219fef11afabfb22ea90c27f716fa5&num=1') mydict = json.loads(resp.text) print(mydict) for tempdict in mydict['newslist']: pic_url = tempdict['picUrl'] resp = requests.get(pic_url) filename = pic_url[pic_url.rfind('/') + 1:] try: with open(filename, 'wb') as fs: fs.write(resp.content) except IOError as e: print(e) if __name__ == '__main__': main()
相关文章推荐
- week03_python解析式
- week03_python生成器
- week03_python内置数据结构_字典
- week03_python内置数据结构_缺省字典顺序字典
- Python之菜鸟入门week03
- week03_python内置数据结构__封装、解构
- week03_python_内建函数
- week03_python内置数据结构_set及操作
- week03_python标准库datetime
- Pydev环境搭建ZendStudio 13+python
- python的socket解决死锁的几个方法
- python面向对象进阶(下)
- python---模块
- Python 创建、读取和写入文件以及yield关键字- 千月的python linux 系统管理指南学习笔记(14)
- python简单读取excel文件
- python随机数整理
- python---download Baidu Post Bar picture
- python cookielib
- Python函数第四节
- Python __getattribute__ vs __getattr__ 浅谈