码迷,mamicode.com
首页 > 编程语言 > 详细

python: 字典,类与 "switch"

时间:2015-10-15 22:00:06      阅读:296      评论:0      收藏:0      [点我收藏+]

标签:

  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!它不是一个类!好吧好吧,报错吧那就!

  结案。

 

python: 字典,类与 "switch"

标签:

原文地址:http://www.cnblogs.com/bolgofzjr/p/4883611.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!