编程学习:从函数到面向对象编程
函数的定义与应用
在编程中,定义自己的函数是一项重要技能。函数能够减少代码的重复,帮助我们构建更模块化的程序。一个命名良好的函数,能让代码更易读、更易理解,无论是对自己还是其他处理代码的人来说都是如此。
我们可以为函数添加参数,使函数更加通用。在调用函数时,通过传递与参数对应的不同参数值,来控制函数的行为。函数调用可以使用位置参数和/或关键字参数。对于可选参数,我们可以为参数定义默认值,这样在调用函数时,如果没有提供该参数的值,Python 会使用默认值。
同时,我们还可以定义返回值的函数。这意味着我们可以使用函数来处理数据,并将结果返回给调用者。如果函数返回一个值,我们可以将其赋值给一个变量。此外,我们还可以将一个函数包装在一个参数周围,以处理并返回另一个函数的值。
例如,我们可以尝试不同的
lissajousPoint()
函数参数,或者添加新的曲线和直线,甚至尝试在三条曲线之间连接三条线,以实现变形三角形的效果。通过不断地实验,我们可以发现更多有趣的结果。
三角函数在编程中也有重要的应用。像
sin()
和
cos()
这样的内置三角函数,可用于绘制圆形、螺旋线、椭圆、正弦波和利萨如曲线等。通过运用三角函数,我们能够生成一些令人惊叹的图案和动画,就像在一些屏幕保护程序中看到的那样。
面向对象编程基础
面向对象编程(OOP)处理的是被称为对象的数据结构。我们可以从类创建新对象,类就像是对象的模板,由一组相关的函数和变量组成。对于我们想要处理的每一类对象,都可以定义一个类,每个新对象都会自动采用该类中定义的特征。
面向对象编程结合了我们之前所学的所有知识,包括变量、条件语句、列表、字典和函数。它通过对现实世界对象进行建模,为我们提供了一种非常有效的程序组织方式。
我们可以使用类来建模具体的对象,如建筑物、人、猫和汽车;也可以用它们来建模更抽象的事物,如银行账户、个性和物理力。虽然类定义了一类对象的一般特征,但我们可以为每个创建的对象分配独特的属性,以区分它们。
以汽车类为例,一个
Car
类可能默认指定所有汽车都有四个轮子、一个挡风玻璃等。但像油漆颜色这样的特征,在不同的汽车之间可能会有所不同。当我们使用
Car
类创建一个新的汽车对象时,就可以选择颜色。这些特征被称为属性,在 Python 中,属性是属于类的变量。我们可以决定哪些属性有预定义的值(如四个轮子和挡风玻璃),哪些属性是在创建新汽车时分配的(如油漆颜色)。
| 类 | 属性 |
|---|---|
| Car 类 | 颜色、发动机类型、型号 |
| Car 对象 1 | 红色、电动、轿车 |
| Car 对象 2 | 蓝色、汽油、轿车 |
| Car 对象 3 | 橙色、柴油、皮卡 |
除了属性,类还可以包含方法。方法是属于类的函数,定义了类可以执行的操作或活动。例如,驾驶员通过转向、加速和制动来控制车辆,所以
Car
类可以包含执行这些操作的定义。
定义和使用 Amoeba 类
现在,让我们定义一个
Amoeba
类,它包含一组属性和方法,用于控制变形虫对象的外观和行为。我们将使用这个类来创建多个变形虫。
定义新类
在 Python 中,我们使用
class
关键字来定义一个类。类名可以随意命名,但与变量和函数名一样,只能使用字母数字和下划线字符。推荐的类命名约定是
UpperCamelCase
,即每个单词的首字母大写,从第一个单词开始。
以下是一个简单的
Amoeba
类定义:
class Amoeba(object):
def __init__(self):
print('amoeba initialized')
这里,
__init__()
方法是一个特殊的方法,它在创建新的变形虫对象时会自动调用。这个方法用于设置属性并在对象创建时执行代码。
创建类的实例
要实例化一个变形虫,我们通过类名调用
Amoeba
类,并将其赋值给一个变量,就像调用一个返回值的函数一样。实例化就是创建一个新实例的意思,实例与对象是同义词。
class Amoeba(object):
def __init__(self):
print('amoeba initialized')
a1 = Amoeba()
当运行这段代码时,Python 会创建一个新的
Amoeba()
实例,并自动调用
__init__()
方法。此时,控制台会显示一条
amoeba initialized
消息。
为类添加属性
属性可以看作是属于对象的变量,它可以包含任何类型的数据,如数字、字符串、列表、字典,甚至其他对象。在
Amoeba
类中,我们可以添加三个属性来保存变形虫的 x 坐标、y 坐标和直径。
class Amoeba(object):
def __init__(self, x, y, diameter):
print('amoeba initialized')
self.x = x
self.y = y
self.d = diameter
a1 = Amoeba(400, 200, 100)
在
__init__()
方法中,
self
参数是必需的,并且总是第一个参数。它提供了对实例特定值的访问。例如,对于变形虫
a1
,
self.x
的值为 400。
访问属性
我们可以使用点符号来访问属性。对于
a1
实例,我们可以分别通过
a1.x
、
a1.y
和
a1.d
来访问 x、y 和 d 属性。
以下代码展示了如何使用这些属性来绘制一个代表变形虫
a1
的圆:
def setup():
size(800, 400)
frameRate(120)
def draw():
background('#004477')
# cell membrane
fill(0x880099FF)
stroke('#FFFFFF')
strokeWeight(3)
circle(a1.x, a1.y, a1.d)
在这个代码中,显示窗口的宽度为 800 像素,高度为 400 像素。较高的帧率 120 有助于使后续添加的变形虫摆动动画更加平滑。
添加具有默认值的属性
就像每辆新车出厂时油箱都是空的一样,我们可以为
Amoeba
类添加一个具有默认值的属性。例如,每个变形虫都有一个默认填充为红色的细胞核。
class Amoeba(object):
def __init__(self, x, y, diameter):
print('amoeba initialized')
self.x = x
self.y = y
self.d = diameter
self.nucleus = '#FF0000'
在
draw()
函数中,我们可以添加代码来绘制细胞核:
def draw():
background('#004477')
# nucleus
fill(a1.nucleus)
noStroke()
circle(a1.x, a1.y, a1.d/2.5)
# cell membrane
fill(0x880099FF)
stroke('#FFFFFF')
strokeWeight(3)
circle(a1.x, a1.y, a1.d)
修改属性值
很多属性的值会随着程序的运行而改变。我们可以直接通过实例使用点符号来修改属性的值。
# nucleus
a1.nucleus = '#00FF00'
fill(a1.nucleus)
这段代码将变形虫
a1
的细胞核颜色修改为绿色。
使用字典作为属性
属性可以包含任何类型的数据,我们可以使用字典属性来组合细胞核的属性。
class Amoeba(object):
def __init__(self, x, y, diameter):
print('amoeba initialized')
self.x = x
self.y = y
self.d = diameter
self.nucleus = {
'fill': ['#FF0000', '#FF9900', '#FFFF00',
'#00FF00', '#0099FF'][int(random(5))],
'x': self.d * random(-0.15, 0.15),
'y': self.d * random(-0.15, 0.15),
'd': self.d / random(2.5, 4)
}
在这个字典中,
fill
键对应一个随机选择的十六进制颜色值,
x
和
y
键对应随机生成的坐标值,
d
键对应随机生成的直径值。这样,每个变形虫的细胞核外观都会有所不同。
graph TD;
A[开始] --> B[定义 Amoeba 类];
B --> C[创建 Amoeba 实例 a1];
C --> D[为 a1 添加属性];
D --> E[访问 a1 属性并绘制变形虫];
E --> F[添加默认属性 nucleus];
F --> G[修改 nucleus 属性值];
G --> H[使用字典作为 nucleus 属性];
H --> I[结束];
通过以上步骤,我们逐步学习了如何定义类、创建对象、添加和修改属性,以及使用字典来组织属性。这些知识为我们进一步实现变形虫模拟程序奠定了基础。在后续的开发中,我们可以继续为
Amoeba
类添加更多的属性和方法,实现变形虫的移动、碰撞检测等功能。
编程学习:从函数到面向对象编程
为 Amoeba 类添加方法
在前面的基础上,我们已经能够创建变形虫对象并设置其属性。接下来,我们将为
Amoeba
类添加方法,以实现变形虫的移动等功能。
方法是属于类的函数,它可以对对象的属性进行操作。例如,我们可以添加一个
move
方法,让变形虫在屏幕上移动。
class Amoeba(object):
def __init__(self, x, y, diameter):
print('amoeba initialized')
self.x = x
self.y = y
self.d = diameter
self.nucleus = {
'fill': ['#FF0000', '#FF9900', '#FFFF00',
'#00FF00', '#0099FF'][int(random(5))],
'x': self.d * random(-0.15, 0.15),
'y': self.d * random(-0.15, 0.15),
'd': self.d / random(2.5, 4)
}
def move(self, dx, dy):
self.x += dx
self.y += dy
在上述代码中,我们定义了一个
move
方法,它接受两个参数
dx
和
dy
,分别表示在 x 轴和 y 轴上的移动距离。在方法内部,我们通过修改
self.x
和
self.y
的值来实现变形虫的移动。
要调用这个方法,我们可以在
draw
函数中添加以下代码:
def draw():
background('#004477')
a1.move(1, 1) # 每次移动 1 个像素
# nucleus
fill(a1.nucleus['fill'])
noStroke()
circle(a1.x + a1.nucleus['x'], a1.y + a1.nucleus['y'], a1.nucleus['d'])
# cell membrane
fill(0x880099FF)
stroke('#FFFFFF')
strokeWeight(3)
circle(a1.x, a1.y, a1.d)
实现多个变形虫的模拟
为了实现多个变形虫的模拟,我们可以创建多个
Amoeba
类的实例,并将它们存储在一个列表中。
amoebas = []
amoebas.append(Amoeba(400, 200, 100))
amoebas.append(Amoeba(600, 250, 200))
def draw():
background('#004477')
for amoeba in amoebas:
amoeba.move(1, 1)
# nucleus
fill(amoeba.nucleus['fill'])
noStroke()
circle(amoeba.x + amoeba.nucleus['x'], amoeba.y + amoeba.nucleus['y'], amoeba.nucleus['d'])
# cell membrane
fill(0x880099FF)
stroke('#FFFFFF')
strokeWeight(3)
circle(amoeba.x, amoeba.y, amoeba.d)
在上述代码中,我们创建了一个
amoebas
列表,并向其中添加了两个变形虫对象。在
draw
函数中,我们遍历这个列表,对每个变形虫对象调用
move
方法,并绘制它们的细胞核和细胞膜。
碰撞检测
为了防止变形虫相互穿过,我们需要实现碰撞检测功能。碰撞检测的基本思路是计算两个变形虫之间的距离,如果距离小于它们的半径之和,则认为发生了碰撞。
import math
def is_colliding(amoeba1, amoeba2):
distance = math.sqrt((amoeba1.x - amoeba2.x) ** 2 + (amoeba1.y - amoeba2.y) ** 2)
return distance < (amoeba1.d / 2 + amoeba2.d / 2)
def draw():
background('#004477')
for i in range(len(amoebas)):
for j in range(i + 1, len(amoebas)):
if is_colliding(amoebas[i], amoebas[j]):
# 处理碰撞,例如反向移动
amoebas[i].move(-1, -1)
amoebas[j].move(-1, -1)
amoebas[i].move(1, 1)
# nucleus
fill(amoebas[i].nucleus['fill'])
noStroke()
circle(amoebas[i].x + amoebas[i].nucleus['x'], amoebas[i].y + amoebas[i].nucleus['y'], amoebas[i].nucleus['d'])
# cell membrane
fill(0x880099FF)
stroke('#FFFFFF')
strokeWeight(3)
circle(amoebas[i].x, amoebas[i].y, amoebas[i].d)
在上述代码中,我们定义了一个
is_colliding
函数,用于判断两个变形虫是否发生碰撞。在
draw
函数中,我们遍历所有变形虫对,检查它们是否发生碰撞。如果发生碰撞,我们让它们反向移动。
总结
通过以上步骤,我们完成了一个简单的变形虫模拟程序。在这个过程中,我们学习了如何定义类、创建对象、添加属性和方法,以及实现碰撞检测等功能。
以下是整个程序的流程图:
graph TD;
A[开始] --> B[定义 Amoeba 类];
B --> C[创建多个 Amoeba 实例并存储在列表中];
C --> D[在 draw 函数中遍历列表];
D --> E[检查变形虫之间的碰撞];
E --> F{是否碰撞};
F -- 是 --> G[处理碰撞,反向移动];
F -- 否 --> H[正常移动变形虫];
H --> I[绘制变形虫的细胞核和细胞膜];
I --> D;
D --> J[结束];
整个学习过程可以总结为以下步骤:
1. 学习函数的定义和使用,包括添加参数、返回值等。
2. 了解面向对象编程的基本概念,如类、对象、属性和方法。
3. 定义
Amoeba
类,创建变形虫对象并设置属性。
4. 为
Amoeba
类添加方法,实现变形虫的移动。
5. 创建多个变形虫对象,实现多个变形虫的模拟。
6. 实现碰撞检测功能,防止变形虫相互穿过。
通过不断实践和探索,我们可以进一步扩展这个程序,例如添加更多的属性和方法,实现更复杂的变形虫行为。
从函数到面向对象编程入门
超级会员免费看

被折叠的 条评论
为什么被折叠?



