7.1 类与实例
前置:3.4 · 约 35 分钟 · 官方对应:类
目标
- 读懂
class定义、__init__与self,知道“调用类即创建实例”。 - 区分实例属性与类属性,方法与普通函数。
- 读懂属性链
client.messages.create(...):每个点都是一次属性访问。
核心概念
定义与实例化
Python · 可运行
python
class Tool:
"""一个可被模型调用的工具。"""
def __init__(self, name, description, func): # 初始化方法:创建实例后自动调用
self.name = name # 实例属性:每个实例各有一份
self.description = description
self.func = func
def run(self, **kwargs): # 方法:第一个参数是实例本身
return self.func(**kwargs)
def schema(self):
return {"name": self.name, "description": self.description}
def get_weather(city):
return f"{city}:晴,22°C"
weather = Tool("get_weather", "查询城市天气", get_weather) # 调用类 → 创建实例
print(weather.name) # 访问属性
print(weather.run(city="上海")) # 调用方法
print(weather.schema())
print(type(weather), isinstance(weather, Tool))self 是什么
self 是方法的第一个参数,指向调用该方法的实例。weather.run(city="上海") 实际上等价于 Tool.run(weather, city="上海")——Python 自动把点号左边的对象作为第一个参数传入。self 只是约定名称。
Python · 可运行
python
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
return self.count
c = Counter()
c.increment()
Counter.increment(c) # 与 c.increment() 完全等价
print(c.count)类属性 vs 实例属性
定义在类体中(方法外)的变量是类属性,所有实例共享;通过 self.x = ... 赋值的是实例属性。读取 obj.x 时先找实例,再找类。
Python · 可运行
python
class Client:
default_base_url = "https://api.anthropic.com" # 类属性
def __init__(self, api_key, base_url=None):
self.api_key = api_key # 实例属性
self.base_url = base_url or self.default_base_url
a = Client("k1")
b = Client("k2", base_url="https://api.deepseek.com/anthropic")
print(a.base_url)
print(b.base_url)
print(vars(a)) # 实例自己的属性字典
print(Client.default_base_url)属性链:对象里套对象
SDK 常把功能按“资源”分组:客户端对象的属性是另一个对象,后者再提供方法。下面是一个与 anthropic 结构相同的极简模拟:
Python · 可运行
python
class Messages:
def __init__(self, client):
self._client = client
def create(self, *, model, max_tokens, messages):
return f"POST {self._client.base_url}/v1/messages model={model} 共 {len(messages)} 条消息"
class FakeAnthropic:
def __init__(self, api_key=None, base_url=None):
self.api_key = api_key
self.base_url = base_url or "https://api.anthropic.com"
self.messages = Messages(self) # 资源对象作为属性挂在客户端上
client = FakeAnthropic(api_key="sk-demo", base_url="https://api.deepseek.com/anthropic")
print(client.messages.create(model="deepseek-flash", max_tokens=1024, messages=[{"role": "user", "content": "hi"}]))
# 拆开看:client → .messages(Messages 实例)→ .create(绑定方法)→ (...) 调用
m = client.messages
f = m.create
print(type(m).__name__, callable(f))易错点
- 方法定义漏写
self:调用时报TypeError: … takes 0 positional arguments but 1 was given。 - 方法内忘了
self.:写count += 1而不是self.count += 1,会被当作局部变量。 - 把可变对象设为类属性:
items = []写在类体中,所有实例共享同一个列表;应在__init__中创建。 - 访问不存在的属性:
AttributeError,3.10 起会提示相近的名字。
Python · 可运行演示报错
python
class Tool:
def run(): # 漏写 self
return "ok"
Tool().run()Python · 可运行
python
class Bad:
history = [] # 类属性:被所有实例共享
a, b = Bad(), Bad()
a.history.append("a 的消息")
print(b.history) # ['a 的消息']对照
| 概念 | Python | JS | Java |
|---|---|---|---|
| 定义 | class A: | class A {} | class A {} |
| 构造 | def __init__(self, x): | constructor(x) {} | A(int x) {} |
| 实例引用 | 显式参数 self | 隐式 this | 隐式 this |
| 创建实例 | A(1)(无 new) | new A(1) | new A(1) |
| 字段声明 | 在 __init__ 中赋值即创建 | 类字段或构造器中赋值 | 必须声明 |
| 访问控制 | 无;_x 约定内部 | #x 私有 | private |
| 静态成员 | 类属性、@staticmethod、@classmethod | static | static |
读代码
python
client = anthropic.Anthropic(
api_key=os.getenv(config["key_env"]),
base_url=config["base_url"],
)
...
resp = client.messages.create(model=model, max_tokens=1024, tools=tools, messages=messages)anthropic.Anthropic:模块anthropic的属性,是一个类;加括号调用 → 执行其__init__,返回实例client。client.messages:客户端实例的属性,是一个“消息资源”对象。.create(...):该资源对象的方法,返回响应对象resp。resp.content、resp.stop_reason:响应对象的属性(7.2 与 7.3 讲它们是什么类)。
练习
练习 1:实现 Tool 类
实现 Tool 类:__init__(self, name, func) 保存属性 name、func;方法 run(self, **kwargs) 调用 func 并返回结果;方法 describe(self) 返回 f"Tool({self.name})"。
练习
class Tool:
def __init__(self, name, func):
pass
快捷键:⌘/Ctrl + Enter 提交检查
练习 2:模拟资源对象
仿照上文的 FakeAnthropic:实现 Messages 类,其 create(self, *, model, messages) 把调用参数记录到 self.calls 列表(元素为 {"model": model, "count": len(messages)}),并返回 "ok";实现 Client 类,__init__ 中创建属性 messages = Messages()。
练习
class Messages:
def create(self, *, model, messages):
return "ok"
class Client:
pass
快捷键:⌘/Ctrl + Enter 提交检查
小结
- 调用类创建实例,
__init__初始化实例属性。 obj.method(x)等价于Class.method(obj, x),所以方法第一个参数是self。- 读取属性先找实例再找类;可变对象不要放在类属性中。
- 属性链逐个点号拆开读:对象 → 属性对象 → 方法 → 调用。