设为首页 收藏本站
查看: 762|回复: 0

[经验分享] python: 字典,类与 "switch"

[复制链接]
发表于 2015-11-29 09:56:19 | 显示全部楼层 |阅读模式
  python中是没有switch语法的,我在练习的时候想使用类似switch的功能,搜索相关内容知道了使用字典可以完成我想要的步骤。于是,开始动手。
  我使用的是python3,并且在练习使用tkinter模块写个小游戏:乒乓球。测试阶段,首先我敲入:



from tkinter import *
  从而加载tkinter模块,并使用 * 使得在之后的代码输入中可以稍打一些代码。在这之后,我构想在创建一个canvas类变量,并在上面画一个矩形,通过左右方向键控制矩形移动从而模拟球拍。测试的完整代码为:



1 from tkinter import *
2
3
4 def move2right(dis):
5     canvas.move(1, dis, 0)
6
7
8 def move2left(dis):
9     canvas.move(1, -dis, 0)
10
11 movement = {'Right': move2right, 'Left': move2left}
12
13
14 def move(event):
15     movement.get(event.keysym)(8)
16
17 tk = Tk()
18 canvas = Canvas(tk, width=500, height=500)
19 canvas.pack()
20 canvas.create_rectangle(100, 100, 200, 120)
21 canvas.bind_all('<KeyPress-Right>', move)
22 canvas.bind_all('<KeyPress-Left>', move)
23
24 tk.mainloop()
  以上测试代码的结果很顺利:使用字典变量movement将两个函数的指针存入字典中。21,22行绑定左右建的触发事件给函数move(),因为bind_all()方法中传递的函数要有一个参数(event),在bind_all()方法内部会将其设置为一个event类,从而存储触发的事件内容,因为以上原因,我定义了move()函数来封装movement.get()方法。15行中,.get()方法可以通过索引key获取相应的value,event.keysym为bind_all()传递给move()函数的event类中的元素,是一个代表相应键盘按键的字符串(这里有效的是'Right' 和 'left')。15行最后的 (8) 是函数的参数。
  在测试成功后,我将这种方法移到了测试乒乓球和球拍反弹的文件中,这里面有乒乓球的Ball类和球拍Paddle类。先贴上最后可以运行的代码:



1 # !/usr/bin/env python3
2 # -*-coding=utf-8-*-
3
4 from tkinter import *
5 import time
6
7
8 class Ball:
9     def __init__(self, canvas, color, paddle):
10         self.canvas = canvas
11         self.canvas_height = self.canvas.winfo_height()
12         self.canvas_width = self.canvas.winfo_width()
13         self.paddle = paddle
14         self.id = canvas.create_oval(10, 10, 25, 25, fill=color)
15         self.canvas.move(self.id, 245, 100)
16         self.hit_bottom = False
17         self.x_pixel_of_one_step = 0  # 小球横向速度
18         self.y_pixel_of_one_step = -3  # 小球纵向速度
19
20     def hit_paddle(self, pos):
21         paddle_pos = self.canvas.coords(self.paddle.id)
22         if paddle_pos[0] <= (pos[0] + pos[2])/2.0 <= paddle_pos[2]:
23             if paddle_pos[1] <= pos[3] < paddle_pos[3] and self.y_pixel_of_one_step > 0:
24                 return True
25             if paddle_pos[1] < pos[1] <= paddle_pos[3] and self.y_pixel_of_one_step < 0:
26                 return True
27         return False
28
29     def draw(self):
30         ball_pos = self.canvas.coords(self.id)  # 提取目前小球的位置
31         # 碰撞到上下边反弹参数设置
32         if ball_pos[1] <= 0 or ball_pos[3] >= self.canvas_height:
33             self.y_pixel_of_one_step = -self.y_pixel_of_one_step
34         # 碰撞到左右边反弹参数设置
35         if ball_pos[0] <= 0 or ball_pos[3] >= self.canvas_width:
36             self.x_pixel_of_one_step = -self.x_pixel_of_one_step
37         # 碰撞到球拍反弹参数设置
38         if self.hit_paddle(ball_pos):
39             self.y_pixel_of_one_step = -self.y_pixel_of_one_step
40         # 移动小球
41         self.canvas.move(self.id, self.x_pixel_of_one_step, self.y_pixel_of_one_step)
42
43
44 class Paddle:
45     def __init__(self, canvas, color):
46         self.canvas = canvas
47         self.canvas_height = canvas.winfo_height()
48         self.canvas_width = canvas.winfo_width()
49         self.id = canvas.create_rectangle(0, 0, 100, 10, fill=color)
50         self.canvas.move(self.id, 250, 250)
51         self.canvas.bind_all('<KeyPress-Right>', self.move)
52         self.canvas.bind_all('<KeyPress-Left>', self.move)
53         self.x_pixel_of_one_step = 0
54         self.y_pixel_of_one_step = 0
55
56     def move2left(self):
57         paddle_pos = self.canvas.coords(self.id)
58         if paddle_pos[0] >= 0:
59             self.canvas.move(self.id, -5, 0)
60
61     def move2right(self):
62         paddle_pos = self.canvas.coords(self.id)
63         if paddle_pos[2] <= self.canvas_width:
64             self.canvas.move(self.id, 5, 0)
65
66     movement = {'Right': move2right, 'Left': move2left}
67
68     def move(self, event):
69         self.movement.get(event.keysym)(self)
70         # print(self.movement[event.keysym])
71
72     def draw(self):
73         pass
74
75
76 tk = Tk()
77 tk.title('Fuck The Ping-Pang')
78 tk.resizable(0, 0)  # 限制画布不能伸缩
79 tk.wm_attributes('-topmost', 1)
80 canvas = Canvas(tk,width=500, height=500, bd=0, highlightthickness=0)
81 # canvas = Canvas(tk, width=500, height=500)
82 canvas.pack()
83 tk.update()
84 paddle = Paddle(canvas, 'black')
85 ball = Ball(canvas, 'black', paddle)
86
87 while True:
88     ball.draw()
89     tk.update_idletasks()
90     tk.update()
91     time.sleep(0.01)
  一切正常,除了56~70行。这几行正是我加入的刚刚所示的方法。我纠结的地方在第69行。这一行的内容我百思不得其解。
    对于类方法的定义,所有类方法的第一个参数必须是一个self(名称可变)参量,这个参量默认指向方法说在的类,便于方法内部相关内容的编写。而在使用方法时,这个self参量是隐藏的,也就是说这个参量并不会对外可见。例如Paddle类中的move2left()函数(56行),在类方法定义中使用move2left()函数时,只需要写self.move2left(),内部的self参数不需要写。但是在69行上,我必须要在参数中加入self才行。重温一下69行:
  



self.movement.get(event.keysym)(self)
  
  这里的self参数是move()方法中的默认参数self,指向所在的Paddle类,是一个函数指针。为什么要显示地写入这个参数呢?
  在字典movement中保存了两个内容,分别是 move2left 函数和 move2right 函数的指针。那么在使用 movement.get('Right') 时,相当于返回了 move2right 。那么,movement.get('Right')() 这个代码就相当于move2right() 这个函数的调用,最后的括号表示前面的内容是一个函数,不加的话运行肯定是过不去的(不能用编译儿,因为python是解释性语言)。对于非类方法的函数,在函数定义时形参中没有设定默认值的参数,在调用这个函数时,必须要在相应的形参位置上传入实参,如果没有传入足够多的实参,那么Python解释器就无法正确运行这个函数从而报错。对于类方法中的函数,因为Python解释器对类的 ”特别对待“,所以在调用类方法的时候,解释器会自动 “跨过” 类方法中第一个默认指向自身类的指针的变量。
  但是纠结的地方来了。在使用字典方法get()时,get 方法仅仅返回字典中对应键(key)的值(value)。在这里返回的是move2left或者move2right函数的地址。解释器运行到这里并从get()方法中出来后,得到了一个函数指针。然而此时解释器已经不知道这个指针是否是类中的方法,它只知道这个函数指针所指向的函数需要一个参数self,所以在与后面的括号()结合并解释成一个函数时,它需要相应个数的实参,所以此时不能忽略那个self参数的输入。
  问题又来了,python中是隐藏数据类型的。并且在这个例子中,move2left 和 move2right 的self参量都没有使用,这时我可不可以不传入self 而传入别的参数,例如: self.movement.get(event.keysym)(20)。虽然这样是无意义的,但是与上一段python解释器的行为并不相冲突。恩,结果倒是没有悬念:运行出错。运行出错,那么原因基本只有一个:在解释器将get()方法与后面的括号结合起来并解释为函数时,解释器将这个函数解释为非类方法,将其作为普通函数,检测它的参数传递个数与定义个数是否一致。在检测参数一致后,程序将由函数指针进入这个函数,然后发现这个函数竟然是一个类方法!那么它就再检查一次向函数传递的参数,这时候发现传递给函数的参数有一个—— 20,而这个类方法的定义的参数只有一个默认的self。解释器接受这个事实,并把20赋值给self。因为脚本运行,程序继续跑(例如之前按的是左键,那么跳入的是move2left()方法)。在move2left 方法中使用了self.canvas.move()方法,解释器这时候发现,self等于20!它不是一个类!好吧好吧,报错吧那就!
  结案。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-144814-1-1.html 上篇帖子: Python中的类(上) 下篇帖子: Python之练习Demo
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表