讲解

类(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 把方法伪装成属性。下一节让类之间建立关系:继承。