讲解
类(class)是把数据和操作数据的函数打包在一起的自定义类型。定义用 class 关键字(类名用大驼峰 UpperCamelCase):class Dog: 里面定义的函数叫方法,第一个参数永远是 self——代表「调用它的那个对象本身」。init 是初始化方法,创建对象时自动执行,负责给对象安上初始属性:self.name = name。创建对象(实例化)写 dog = Dog('旺财'),注意调用时不需要手动传 self,Python 会自动把 dog 塞进去。
对象创建后,属性可以读(dog.name)可以改(dog.name = '来福'),方法用 dog.bark() 调用,方法内部通过 self.name 访问同一对象的属性。self 机制要真正理解:Dog.bark(dog) 和 dog.bark() 完全等价,后者只是语法糖。方法之外,直接写在类体里的变量是「类属性」,被所有实例共享(比如计数器、常量配置);写在 init 里挂在 self 上的是「实例属性」,每个对象一份。误把可变对象(列表)当类属性,会让所有实例共享同一个列表,是经典坑。
什么时候用类?当一组数据和对数据的操作天然绑在一起时——用户、订单、游戏角色、数据库连接。简单场景别硬上类:一组纯数据用字典或 namedtuple 就行,几个独立函数也不需要包进类里。另外提一下 @property 装饰器:它把方法伪装成属性,dog.age 背后实际是调用方法,可以在「属性」被读取时做计算或校验,是 Python 控制属性访问的优雅方式(比 Java 式 getter/setter 简洁)。
示例
class Dog:
"""一只会叫、会长大的狗。"""
species = '犬科' # 类属性:所有实例共享
def __init__(self, name, age):
self.name = name # 实例属性:每个对象一份
self.age = age
def bark(self):
return f'{self.name}:汪汪!'
def grow(self):
self.age += 1
return self.age
# 实例化与调用
wangcai = Dog('旺财', 2)
laifu = Dog('来福', 5)
print(wangcai.bark())
print(f'{laifu.name} 今年 {laifu.age} 岁,长大后 {laifu.grow()} 岁')
# 类属性共享,实例属性独立
print('种类:', wangcai.species, laifu.species)
print('名字各自独立:', wangcai.name, laifu.name)
# dog.bark() 等价于 Dog.bark(dog)
print('手动传 self:', Dog.bark(wangcai))
# @property:把方法伪装成属性
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return 3.14159 * self.radius ** 2
@property
def diameter(self):
return self.radius * 2
c = Circle(3)
print('像属性一样访问:', c.area, c.diameter)
c.radius = 4
print('改半径后自动重算:', c.diameter)
# 类属性误用可变对象的反面教材(注释掉的是坑,演示正确写法)
class Team:
def __init__(self, name):
self.name = name
self.members = [] # 正确:实例属性,每队一份
# members = [] 写在类体里就是所有队共享同一个列表——别这么干
def join(self, member):
self.members.append(member)
a = Team('甲队')
b = Team('乙队')
a.join('小明')
print('甲队:', a.members, ',乙队不受影响:', b.members)
常见坑
- 方法忘写 self:def bark(): 定义后 dog.bark() 会报「多传了一个参数」。实例方法第一个参数永远是 self。
- 类属性当实例属性用:类体里写 members = [],所有实例共享同一个列表,甲队加人乙队可见。可变属性挂 self 上。
- 以为 init 是构造函数:对象其实由 new 创建,init 只是初始化。日常开发只需要管 init,但概念上别搞混。
- 过度设计:两个属性一个函数的小结构,namedtuple 或字典更轻;类是留给「数据 + 行为」真正绑定的场景的。
小结
class 定义类型,init 初始化,self 指向调用者;类属性共享、实例属性独立;@property 把方法伪装成属性。下一节让类之间建立关系:继承。