闭包, lamda表达式以及装饰器之间异同
- 异同
- 闭包:是在函数内部引用了一个变量且能够让里面的嵌套函数使用, 外面无法使用该变量.
- lamda: 就是一个匿名函数, 在使用的过程当中不需要定义函数名.
- 装饰器: 也是闭包, 不过里面的变量需要传递进去, 一般时候. 这个变量也是可执行的函数.
三者之间, 闭包和装饰器十分类似, 或者说, 装饰器就是通过闭包实现.
闭包更倾向于对变量的局部复用.
装饰器倾向于对代码的多次复用.
lamda的实现方式和闭包类似, 但它大多时候只是一个比较方便的表达式.
- 场景:
- lamda:通常我在使用map函数的时候搭配lamda,因为lamda的简便, 会让代码十分简洁.
- 闭包: 如果当前代码中有一个变量是经常使用的, 且不会变动的. 可以考虑封成一个闭包, 把变量写死在里面.
- 装饰器: 装饰器的使用场景很广. 当该代码段需要在另一段代码前置执行的时候, 都可以考虑用装饰器的方式装饰其他函数.
- 单例模式
装饰器:
闭包和装饰器实现单例模式比较简单, 装饰器内设置isFlag, 并进行判断. 当isFlag为最初状态则继续, 否则返回.
如果用lamda实现单例, 应该首先解决变量和判断问题. 最后根据状态返回空或一个lamda生成的表达式.
算法
N个现有N 个最大长度为M的字符串组成的数组S,其中可能包含重复相同的字符串。设计算法,将数组S中的字符串进行去重操作,得到不含有相同字符串的字符串集合。
包含重复相同的字符串的两种情况:
- 对于列表S内的字符串, 可能存完全相同的字符串,需去重.
- 对于列表S内的字符串内的字符, 可能存在相同字符,需去重.
Python中:
-
情况1. 直接使用set函数去重.通过对比hash实现, 时间复杂度O(1).
-
情况2. 需要使用双循环. 时间负责度O(mn)
第一循环获取N个字符串.
第二次循环获取M个字符.
然后通过获取该字符第一个下标的方式完成去重.
如下:
def func(list):
for n in len(list)-1:
st = list[n]
new_st = ''
for i in st:
index = st.find(i)
new_st[index] = st[index]
list[n] = new_st
贪吃蛇
贪吃蛇通过在方形棋盘格上虚拟出蛇和食物的场景,玩家控制蛇的前进方向,蛇在“吃”到食物后变长,同时刷新新的食物,如此往复,直到蛇头撞到障碍物,结束游戏。
根据如下要求完成服务端的设计:
- 游戏终端是浏览器;
- 游戏逻辑运行和数据存储在服务端;
- 以合适的方法用单主机支持20 个连接(不必在同一场景内)
- 采用Django框架完成该服务器.
必要的数据结构:
-
用户:
id, 头像(金币等) , 战绩. -
蛇:
用户id, 长度, 状态(是否死亡) -
食物:
数量(对应棋盘), 刷新时间. -
流程:
用户打开浏览器进入该界面, 通过session获取到用户id. 从而显示对应的头像,战绩,金币等.
用户开始游戏, 创建棋盘, 初始化蛇的状态并随机分布等量食物.
开始比赛.
比赛结束, 保存该战局信息.
- 对于我来说, 该程序难点在于. 比赛的过程的处理.
用户的蛇的实时位置.
如果逻辑处理放在服务器上的话, 根据每个用户控制的蛇的对应棋盘所在点进行判断的话. 那么首先要解决的就是延时问题.
如果蛇每移动一个坐标都需要上传新的位置到服务器的话, 那么对于服务器来说也是一个不小的负担.
如果一定需要由后端处理该逻辑的话.
我觉得可以由方向来判断蛇的状态.
只获取蛇的朝向.
假设蛇的移动速度是固定的, 每秒1格.
当游戏开始时候, 初始化蛇. 并获取蛇所在的坐标,和默认方向.
每当蛇进行转弯的时候.
后端计算出来方向改变的时间. 在这段时间内超这个方向移动了多少格. 然后计算与边框的距离.距离小于0, 则蛇状态为false.
每当蛇的方向发生变化的时候, 都重新计算一下.但是这个方法不能实现.. 撞自己逻辑.
所以需要在这个基础上, 添加对单元格的判断. 根据蛇的长度, 以及行走的单元格. 判断哪个格子的状态为false, 当蛇行走到该单元格, 则蛇状态为false.
- 优化方面:
-
如果网络条件较差, 一方面可以将一部分逻辑放在前端判断.一方面可以减少用户请求次数.
-
如果多用户在同场景游戏, 数据库需要引入棋盘, 棋盘大小, 以及 每场游戏的战绩等.
多用户间互动.
除了对棋盘边框进行判断之外.
还要对其他用户的蛇的身体进行判断. (类似于上面 自己蛇身体的单元格false)