入门会造类、会用
自己了。这一节学方法的更多用法,以及什么时候该用类。
方法里可以调用同一个对象的另一个方法,用 自己.方法名():
类 学生
初始化(名字, 分数)
函数 等级()
如果 自己.分数 >= 90
返回 "优秀"
否则 如果 自己.分数 >= 60
返回 "及格"
返回 "继续加油"
函数 名片()
返回 @"{自己.名字}:{自己.分数} 分({自己.等级()})" # 调用了 自己.等级()
字段不只能读,也能改(和改字典里的值一样):
类 学生
初始化(名字, 分数)
函数 补考(新分数)
自己.分数 = 新分数 # 直接改
函数 过生日()
自己.年龄 = 自己.年龄 + 1 # 复合赋值也支持
改的是这个对象自己的字段,不影响其他对象。
类的初始化和方法遵守普通函数的同一条规则:一次调用要么全按位置传值,要么全部写成 参数名 = 值;全按名字时可以调换顺序,但不能混写。
类 学生
初始化(名字, 分数)
函数 补考(新分数)
自己.分数 = 新分数
返回 自己.分数
设 小明 = 学生(分数 = 92, 名字 = "小明")
打印(小明.名字, 小明.分数) # 小明 92
打印(小明.补考(新分数 = 95)) # 95
这里造对象时把 分数 写在 名字 前面也没关系,因为两个值都点了名。详细错误规则见函数入门的关键字参数。
方法可以像值一样取出来、存起来:
类 学生
初始化(名字)
函数 名字大写()
返回 大写(自己.名字)
设 小明 = 学生("xiaoming")
设 f = 小明.名字大写 # 取出方法(不带括号)
打印(f()) # XIAOMING
取出时「自己」已经绑定好是哪个对象了,所以 f() 不用再传对象。
CNplus 的类没有继承(不像 Python 的 class B(A))。
想「复用」另一个类的能力?用组合——把它当字段放进来,或者把对象传进方法:
类 班级
初始化(名称)
自己.成员 = [] # 字段里装一堆学生对象
函数 加入(一名学生)
追加(自己.成员, 一名学生)
「班级有一堆学生」用「班级里放一个列表、列表里装学生」来表达,而不是「班级继承列表」。这是刻意的选择:组合比继承简单、好懂,将来需要时再加。
一个类里,下面这些都会报 CN0307(重复声明):
初始化;类 学生
初始化(名字) # 「名字」自动成为字段
函数 名字() # ❌ 字段「名字」和这个方法同名 → CN0307
返回 自己.名字
不着急,两条路都通:
对象.做事() 读起来自然。没有谁更高级。类是一种组织方式,帮你在程序变大时保持条理。前几章的写法照样对,类只是多给你一个选择。
学过 Python 的人,看这里——这一节学的,用 Python 写是这样。零基础可以直接跳过,去下面做「练习」。
先把这一节串成一个完整程序(CNplus):
类 学生
初始化(名字, 分数)
函数 等级()
如果 自己.分数 >= 60
返回 "及格"
返回 "不及格"
设 小明 = 学生("小明", 92)
打印(小明.等级())
同一个程序,用 Python 写:
class 学生: # 类 学生
def __init__(self, 名字, 分数): # 初始化(名字, 分数)
self.名字 = 名字 # ← 手动转存,CNplus 自动
self.分数 = 分数
def 等级(self): # 函数 等级()
if self.分数 >= 60: # 自己.分数
return "及格"
return "不及格"
小明 = 学生("小明", 92) # 设 小明 = 学生("小明", 92)
print(小明.等级()) # 小明.等级()
| CNplus | Python |
|---|---|
类 学生 |
class 学生: |
初始化(名字, 分数)(参数自动成字段) |
def __init__(self, 名字, 分数) + 手动 self.名字 = 名字 |
自己.名字 |
self.名字 |
函数 方法()(不写 self) |
def 方法(self): |
| 无继承(用组合) | 有 class B(A) 继承 |
三条核心差异:① 初始化参数自动成字段(免写 self.x = x);② 方法签名不写 self(自己 是隐式关键字);③ 没有继承。会 CNplus 的类,转 Python 只差「手动写 self.xxx = xxx」和「方法加 self 形参」两步。
下一步:做练习。