杀手:恶魔出没的世界免安装绿色中文版
1.12G · 2025-10-25
确实可以,但如果理解了它们背后的“职责分层思想”,你就会发现:
下面聊聊它们的区别、联系、使用场景,以及一些常见的混淆点。
类属性是属于类本身的数据,而不是某个具体对象的,它在所有实例之间共享同一份。
class Car:
wheels = 4 # 类属性,所有汽车默认都有 4 个轮子
def __init__(self, brand):
self.brand = brand # 实例属性,每辆车品牌不同
a = Car("Toyota")
b = Car("Tesla")
print(a.wheels, b.wheels) # 4 4
Car.wheels = 3 # 修改类属性
print(a.wheels, b.wheels) # 3 3 => 所有实例都变了
定义通用的、不会随实例改变的属性
存放跨实例共享的状态或统计信息
class Connection:
active_count = 0 # 当前连接数
def __init__(self):
Connection.active_count += 1
def close(self):
Connection.active_count -= 1
c1 = Connection()
c2 = Connection()
print(Connection.active_count) # 2
| 属性类型 | 定义位置 | 归属 | 是否共享 | 典型用途 |
|---|---|---|---|---|
| 类属性 | 类体内 | 类 | 是 | 全局状态、常量 |
| 实例属性 | __init__ 内 | 实例 | 否 | 对象特有数据 |
类方法使用 @classmethod 装饰,第一个参数是 cls(类本身),不是 self(实例)。
class Car:
wheels = 4
@classmethod
def change_wheels(cls, new_count):
cls.wheels = new_count
Car.change_wheels(6)
print(Car.wheels) # 6
与实例方法不同,类方法可以直接操作类属性,即使没有创建对象。
创建“命名构造器”(Factory Methods)
class Car:
def __init__(self, brand, model):
self.brand = brand
self.model = model
@classmethod
def from_string(cls, s):
brand, model = s.split("-")
return cls(brand, model)
c = Car.from_string("Tesla-Model3")
print(c.brand, c.model)
类方法天然支持继承,不像静态方法那样固定绑定在父类。
class Animal:
species = "Animal"
@classmethod
def describe(cls):
return f"This is a {cls.species}"
class Dog(Animal):
species = "Dog"
print(Dog.describe()) # 输出:This is a Dog
静态方法使用 @staticmethod 装饰,它不依赖实例也不依赖类。
就是一个放在类里面的普通函数,用于逻辑分组或语义清晰。
class Math:
@staticmethod
def add(a, b):
return a + b
print(Math.add(2, 3)) # 5
举个现实例子。假设我们在做一个配置系统:
class Config:
default_path = "/etc/app.conf"
def __init__(self, name, path=None):
self.name = name
self.path = path or self.default_path
@classmethod
def load_default(cls):
return cls("default", cls.default_path)
default_path 是类属性(所有配置共享);load_default() 是类方法(它不依赖某个配置实例);Config.load_default() 就能直接构造出默认配置对象。很多同学在学完类属性后,会疑惑:
因为 @dataclass 的写法看起来就像定义“类变量”,这确实容易混淆,但实际上,它只是给实例属性设置了默认值。
来看看实际例子。
from dataclasses import dataclass
@dataclass
class Config:
name: str
version: str = "1.0"
这里的 version = "1.0" 是 实例属性的默认值,不是类属性。
每次实例化都会创建新的 Config(name, version)。
c1 = Config("A")
c2 = Config("B")
print(c1.version, c2.version) # 1.0 1.0
Config.version = "2.0"
print(c1.version) # 1.0,不受影响
如果希望所有实例共享某个值,比如“总产量”或“车型类别”,
那必须明确告诉 @dataclass:
做法是使用 typing.ClassVar。
from dataclasses import dataclass
from typing import ClassVar
@dataclass
class Car:
brand: str
color: str = "white"
# 真正的类属性
total_cars: ClassVar[int] = 0
def __post_init__(self):
# 在初始化后修改类属性
Car.total_cars += 1
结果就是这样
a = Car("Toyota")
b = Car("Honda")
print(Car.total_cars) # 2
如果不加 ClassVar,则 total_cars 会被错误地当作实例属性,
每个对象都会有自己的独立计数。
| 需求 | 推荐用法 |
|---|---|
| 每个对象独有的数据 | 实例属性 + 实例方法 |
| 所有实例共享的常量或统计信息 | 类属性 |
| 定义额外的构造器(工厂函数) | 类方法 |
| 与类相关但独立的工具逻辑 | 静态方法 |
| 框架定义数据结构(如 dataclass / pydantic) | 实例属性 + 类型注解 |
| 不希望字段参与序列化 / 验证 | ClassVar 类属性 |
类属性与类方法并非“语法糖”,而是对象系统分层思想的体现:
┌──────────────────────────────┐
│ 【类(Class)】 │
│ │
│ ┌───────────────────────┐ │
│ │ 类属性(共享数据) │ │
│ │ ─ 归属:类本身 │ │
│ │ ─ 所有实例共享 │ │
│ │ ─ 典型用途:常量/统计 │ │
│ └───────────────────────┘ │
│ │
│ ┌───────────────────────┐ │
│ │ 类方法(类级行为) │ │
│ │ ─ 参数:cls │ │
│ │ ─ 可访问类属性 │ │
│ │ ─ 常用于工厂方法、配置 │ │
│ │ 继承友好(cls动态绑定) │ │
│ └───────────────────────┘ │
│ │
│ ┌───────────────────────┐ │
│ │ 静态方法(独立逻辑) │ │
│ │ ─ 无self/cls参数 │ │
│ │ ─ 不访问实例或类属性 │ │
│ │ ─ 用于工具函数逻辑分组 │ │
│ └───────────────────────┘ │
│ │
│ ↓ 实例化产生对象 │
└──────────────┬───────────────┘
│
│
┌──────▼────────┐
│ 【实例(Object)】 │
│ │
│ 实例属性(私有数据)│
│ ─ 归属:对象自身 │
│ ─ 每个实例独立 │
│ ─ 用于存储状态 │
│ │
│ 实例方法 │
│ ─ 参数:self │
│ ─ 访问实例+类属性 │
│ ─ 操作对象行为 │
└──────────────────┘
| 调用形式 | 所属范围 | 能访问实例属性? | 能访问类属性? | 常见场景 |
|---|---|---|---|---|
obj.method() | 实例方法 | 操作具体对象 | ||
Class.method(obj) | 实例方法 | 不常见等价写法 | ||
Class.classmethod() | 类方法 | 工厂方法、初始化、配置 | ||
obj.classmethod() | 类方法 | 合法,但语义上应通过类调用 | ||
Class.staticmethod() | 静态方法 | 工具函数、逻辑分组 | ||
obj.staticmethod() | 静态方法 | 语法允许,不推荐 | ||
Class.attr | 类属性 | (只读) | 共享配置或常量 | |
obj.attr | 实例属性 | (只读访问) | 对象状态 |
明确意图:
命名约定:
from_xxx, create_xxx, get_xxx(类级别)validate_xxx, calculate_xxx访问规范:
ClassName.attr访问ClassName.method()调用ClassName.method()调用@dataclass注意事项:
ClassVar明确标识类属性__post_init__中
1.12G · 2025-10-25
140M · 2025-10-25
21.8G · 2025-10-25
2025-10-25
2025/26 冬春航季即将启动,国航 C919 新增广州、西安、长沙等新航点
部分 Win11 23H2,Windows Server 2016/2022 安装微软 10 月累积更新失败,严重至“变砖”