Python教程35:类方法与静态方法
“工欲善其事,必先利其器。”
Python提供了三种方法类型:实例方法、类方法、静态方法。今天我们学习类方法(@classmethod)和静态方法(@staticmethod),理解它们的区别和使用场景。
1. 三种方法类型对比
实例方法(Instance Method)
我们最常用的方法:
1class MyClass:
2 def instance_method(self):
3 """
4 实例方法
5 - 第一个参数是self(实例本身)
6 - 可以访问实例属性和类属性
7 - 通过实例调用
8 """
9 print(f"Called instance_method of {self}")
10 return "instance method"
11
12obj = MyClass()
13obj.instance_method() # 正常调用
类方法(Class Method)
使用@classmethod装饰器:
1class MyClass:
2 @classmethod
3 def class_method(cls):
4 """
5 类方法
6 - 第一个参数是cls(类本身)
7 - 可以访问类属性,不能访问实例属性
8 - 通过类或实例调用
9 """
10 print(f"Called class_method of {cls}")
11 return "class method"
12
13# 通过类调用
14MyClass.class_method()
15
16# 通过实例调用也可以
17obj = MyClass()
18obj.class_method()
静态方法(Static Method)
使用@staticmethod装饰器:
1class MyClass:
2 @staticmethod
3 def static_method():
4 """
5 静态方法
6 - 没有self或cls参数
7 - 不能访问实例或类的状态
8 - 通过类或实例调用
9 - 就是普通函数,只是放在类的命名空间里
10 """
11 print("Called static_method")
12 return "static method"
13
14# 通过类调用
15MyClass.static_method()
16
17# 通过实例调用也可以
18obj = MyClass()
19obj.static_method()
对比总结
| 特性 | 实例方法 | 类方法 | 静态方法 |
|---|---|---|---|
| 第一个参数 | self | cls | 无 |
| 访问实例属性 | ✓ | ✗ | ✗ |
| 访问类属性 | ✓ | ✓ | ✗ |
| 调用方式 | 实例 | 类/实例 | 类/实例 |
| 使用场景 | 操作实例数据 | 工厂方法、操作类数据 | 工具函数 |
2. 类方法详解
基本用法
1class Date:
2 """日期类"""
3
4 def __init__(self, year, month, day):
5 self.year = year
6 self.month = month
7 self.day = day
8
9 @classmethod
10 def from_string(cls, date_string):
11 """
12 替代构造函数(工厂方法)
13 - cls是Date类本身
14 - 可以创建实例
15 - 解析字符串创建对象
16 """
17 year, month, day = map(int, date_string.split('-'))
18 return cls(year, month, day) # 调用__init__
19
20 @classmethod
21 def today(cls):
22 """
23 获取今天的日期
24 - 类方法可以有多个
25 - 提供不同的实例化方式
26 """
27 import datetime
28 today = datetime.date.today()
29 return cls(today.year, today.month, today.day)
30
31 def __str__(self):
32 return f"{self.year}-{self.month:02d}-{self.day:02d}"
33
34# 使用不同的构造方式
35date1 = Date(2024, 1, 15) # 普通构造
36date2 = Date.from_string("2024-01-15") # 类方法构造
37date3 = Date.today() # 类方法构造
38
39print(date1) # 2024-01-15
40print(date2) # 2024-01-15
41print(date3) # 当前日期
类方法的优势:
- 替代构造函数:提供多种实例化方式
- 工厂方法:根据不同参数创建不同对象
- 操作类属性:修改类级别的状态
类方法访问类属性
1class Employee:
2 """员工类"""
3
4 # 类属性
5 company_name = "TechCorp"
6 employee_count = 0
7
8 def __init__(self, name):
9 self.name = name
10 Employee.employee_count += 1
11
12 @classmethod
13 def get_employee_count(cls):
14 """
15 获取员工总数
16 - 访问类属性
17 - 不需要创建实例
18 """
19 return cls.employee_count
20
21 @classmethod
22 def set_company_name(cls, name):
23 """
24 设置公司名称
25 - 修改类属性
26 - 影响所有实例
27 """
28 cls.company_name = name
29
30# 使用
31print(Employee.get_employee_count()) # 0
32
33emp1 = Employee("Alice")
34emp2 = Employee("Bob")
35
36print(Employee.get_employee_count()) # 2
37
38Employee.set_company_name("NewTech")
39print(Employee.company_name) # NewTech
继承中的类方法
1class Animal:
2 """动物基类"""
3
4 species_count = 0
5
6 def __init__(self, name):
7 self.name = name
8 Animal.species_count += 1
9
10 @classmethod
11 def create_multiple(cls, names):
12 """
13 批量创建
14 - cls在子类中是子类本身
15 - 实现多态
16 """
17 return [cls(name) for name in names]
18
19class Dog(Animal):
20 """狗类"""
21 pass
22
23class Cat(Animal):
24 """猫类"""
25 pass
26
27# 创建多个实例
28dogs = Dog.create_multiple(["Buddy", "Max", "Charlie"])
29cats = Cat.create_multiple(["Whiskers", "Luna"])
30
31print([dog.name for dog in dogs]) # ['Buddy', 'Max', 'Charlie']
32print([cat.name for cat in cats]) # ['Whiskers', 'Luna']
33print(type(dogs[0])) # <class '__main__.Dog'>(不是Animal)
3. 静态方法详解
基本用法
1class MathUtils:
2 """数学工具类"""
3
4 @staticmethod
5 def is_prime(n):
6 """
7 判断质数
8 - 不需要访问类或实例属性
9 - 纯工具函数
10 - 放在类里是为了组织代码
11 """
12 if n < 2:
13 return False
14 for i in range(2, int(n ** 0.5) + 1):
15 if n % i == 0:
16 return False
17 return True
18
19 @staticmethod
20 def factorial(n):
21 """计算阶乘"""
22 if n <= 1:
23 return 1
24 return n * MathUtils.factorial(n - 1)
25
26# 使用(不需要创建实例)
27print(MathUtils.is_prime(17)) # True
28print(MathUtils.factorial(5)) # 120
静态方法的特点:
- 工具函数:与类相关但不需要访问类状态
- 命名空间:组织相关函数
- 语义清晰:表明函数属于这个类
静态方法vs普通函数
1# 方式1:普通函数
2def validate_email(email):
3 return '@' in email
4
5# 方式2:静态方法
6class User:
7 @staticmethod
8 def validate_email(email):
9 """
10 验证邮箱
11 - 与User相关
12 - 但不需要访问User的属性
13 - 用静态方法组织代码更清晰
14 """
15 return '@' in email
16
17# 使用
18print(validate_email("test@example.com")) # 方式1
19print(User.validate_email("test@example.com")) # 方式2(更清晰)
何时用静态方法:
- 函数逻辑上属于这个类
- 但不需要访问实例或类的状态
- 想把相关函数组织在类的命名空间下
4. 实战示例
示例1:配置管理类
1class Config:
2 """配置管理类"""
3
4 # 类属性:配置数据
5 _config = {
6 "debug": False,
7 "database": "localhost",
8 "port": 5432
9 }
10
11 @classmethod
12 def get(cls, key, default=None):
13 """
14 获取配置(类方法)
15 - 访问类属性
16 - 不需要创建实例
17 """
18 return cls._config.get(key, default)
19
20 @classmethod
21 def set(cls, key, value):
22 """设置配置"""
23 cls._config[key] = value
24
25 @classmethod
26 def load_from_file(cls, filename):
27 """
28 从文件加载配置(工厂方法)
29 - 类方法的典型应用
30 """
31 import json
32 with open(filename) as f:
33 cls._config = json.load(f)
34
35 @staticmethod
36 def validate_port(port):
37 """
38 验证端口号(静态方法)
39 - 纯工具函数
40 - 与配置相关但不需要访问配置数据
41 """
42 return isinstance(port, int) and 0 < port < 65536
43
44# 使用
45print(Config.get("database")) # localhost
46Config.set("debug", True)
47
48if Config.validate_port(8080):
49 Config.set("port", 8080)
示例2:日志类
1import datetime
2
3class Logger:
4 """日志类"""
5
6 # 类属性:日志级别
7 LOG_LEVEL = "INFO"
8
9 def __init__(self, name):
10 """实例方法:特定模块的日志"""
11 self.name = name
12
13 def log(self, message):
14 """实例方法:记录日志"""
15 timestamp = Logger.get_timestamp()
16 print(f"[{timestamp}] [{self.name}] {message}")
17
18 @classmethod
19 def set_level(cls, level):
20 """类方法:设置全局日志级别"""
21 cls.LOG_LEVEL = level
22
23 @staticmethod
24 def get_timestamp():
25 """
26 静态方法:获取时间戳
27 - 工具函数
28 - 不需要访问类或实例状态
29 """
30 return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
31
32# 使用
33logger1 = Logger("Module1")
34logger2 = Logger("Module2")
35
36logger1.log("Starting") # 实例方法
37logger2.log("Processing")
38
39Logger.set_level("DEBUG") # 类方法
40print(Logger.get_timestamp()) # 静态方法
示例3:单例模式
1class Database:
2 """数据库连接(单例模式)"""
3
4 _instance = None # 类属性:单例实例
5
6 def __init__(self, connection_string):
7 if Database._instance is not None:
8 raise Exception("Database is a singleton!")
9 self.connection_string = connection_string
10 Database._instance = self
11
12 @classmethod
13 def get_instance(cls):
14 """
15 获取单例实例(类方法)
16 - 确保只有一个实例
17 - 类方法的经典应用
18 """
19 if cls._instance is None:
20 cls._instance = cls("default_connection")
21 return cls._instance
22
23 @classmethod
24 def reset_instance(cls):
25 """重置实例(主要用于测试)"""
26 cls._instance = None
27
28# 使用
29db1 = Database.get_instance()
30db2 = Database.get_instance()
31
32print(db1 is db2) # True(同一个实例)
5. 选择指南
何时使用实例方法
1class BankAccount:
2 def __init__(self, balance):
3 self.balance = balance
4
5 def deposit(self, amount):
6 """
7 需要修改实例状态 → 实例方法
8 """
9 self.balance += amount
何时使用类方法
1class Person:
2 count = 0
3
4 def __init__(self, name):
5 self.name = name
6 Person.count += 1
7
8 @classmethod
9 def from_birth_year(cls, name, birth_year):
10 """
11 替代构造函数 → 类方法
12 """
13 age = 2024 - birth_year
14 return cls(name)
15
16 @classmethod
17 def get_count(cls):
18 """
19 访问/修改类属性 → 类方法
20 """
21 return cls.count
何时使用静态方法
1class StringUtils:
2 @staticmethod
3 def is_palindrome(s):
4 """
5 工具函数,不需要访问类/实例状态 → 静态方法
6 """
7 return s == s[::-1]
6. 最佳实践
- 优先使用实例方法:默认选择
- 需要访问类属性时用类方法:如计数器、配置
- 工厂方法用类方法:替代构造函数
- 工具函数用静态方法:与类相关但独立的函数
- 避免滥用:不要为了用而用
7. 与Golang对比
Golang没有类的概念,但有类似的模式:
1// Go:接收者方法
2type Person struct {
3 Name string
4}
5
6// 值接收者方法(类似实例方法)
7func (p Person) GetName() string {
8 return p.Name
9}
10
11// 指针接收者方法
12func (p *Person) SetName(name string) {
13 p.Name = name
14}
15
16// 包级函数(类似静态方法)
17func NewPerson(name string) *Person {
18 return &Person{Name: name}
19}
8. 小结
今天我们学习了类方法和静态方法:
- 三种方法:实例方法、类方法、静态方法
- 类方法:@classmethod,访问类属性,工厂方法
- 静态方法:@staticmethod,工具函数
- 选择指南:根据需要访问的状态选择
- 实战应用:配置管理、日志、单例模式
掌握这三种方法类型,能让代码更清晰、更合理。
练习题:
- 创建一个Temperature类,实现摄氏度和华氏度的转换(类方法)
- 实现一个计数器类,跟踪总共创建了多少个实例(类方法)
- 创建一个工具类,包含字符串验证的静态方法
思考题:
为什么单例模式要用类方法而不是静态方法实现?
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
