1. 类方法基础概念
1.1 什么是类方法
类方法是与类关联的方法,而不是与实例关联。它接收类本身(通常命名为cls)作为第一个参数,而不是实例(self)。
1.2 与实例方法的区别
2. 类方法的创建与使用
2.1 基本语法
classMyClass: @classmethoddefclass_method(cls, arg1, arg2):# cls 是类本身,不是实例# 可以访问类属性,但不能访问实例属性returnf"类方法被调用,类名: {cls.__name__}"
2.2 简单示例
classEmployee: company = "ABC Corporation"# 类属性def__init__(self, name, salary): self.name = name # 实例属性 self.salary = salary # 实例属性 @classmethoddefget_company_info(cls):# 类方法只能访问类属性,不能访问实例属性returnf"公司名称: {cls.company},员工类: {cls.__name__}"defget_employee_info(self):# 实例方法可以访问实例属性和类属性returnf"姓名: {self.name},公司: {self.company}"# 使用类方法print(Employee.get_company_info()) # 通过类调用# 创建实例emp = Employee("张三", 5000)# 也可以通过实例调用类方法print(emp.get_company_info()) # 通过实例调用# 实例方法只能通过实例调用print(emp.get_employee_info())
3. 类方法的主要用途
3.1 替代构造函数的工厂方法
classDate:def__init__(self, year, month, day): self.year = year self.month = month self.day = day @classmethoddeffrom_string(cls, date_string):"""从字符串'YYYY-MM-DD'创建Date对象""" year, month, day = map(int, date_string.split('-'))return cls(year, month, day) # 相当于 Date(year, month, day) @classmethoddeffrom_timestamp(cls, timestamp):"""从时间戳创建Date对象"""import datetime dt = datetime.datetime.fromtimestamp(timestamp)return cls(dt.year, dt.month, dt.day)def__str__(self):returnf"{self.year}-{self.month:02d}-{self.day:02d}"# 使用不同的工厂方法创建对象date1 = Date(2023, 10, 15)date2 = Date.from_string("2023-10-20")date3 = Date.from_timestamp(1697788800) # 2023-10-20的时间戳print(date1) # 2023-10-15print(date2) # 2023-10-20print(date3) # 2023-10-20
3.2 类级别的配置和工具函数
classMathOperations: PI = 3.14159 E = 2.71828 @classmethoddefcircle_area(cls, radius):"""计算圆面积"""return cls.PI * radius ** 2 @classmethoddefset_precision(cls, pi_precision, e_precision):"""设置数学常量的精度""" cls.PI = round(3.141592653589793, pi_precision) cls.E = round(2.718281828459045, e_precision) @classmethoddefget_constants(cls):"""获取所有数学常量"""return {'PI': cls.PI,'E': cls.E,'GOLDEN_RATIO': 1.61803 }# 使用类方法print(f"圆面积 (r=5): {MathOperations.circle_area(5)}")# 修改配置MathOperations.set_precision(pi_precision=4, e_precision=4)print(f"更新后的PI: {MathOperations.PI}")# 获取所有常量print(f"数学常量: {MathOperations.get_constants()}")
3.3 继承中的多态行为
classShape: @classmethoddefcreate_default(cls):"""创建默认形状 - 在子类中可以有不同的实现"""raise NotImplementedError("子类必须实现此方法") @classmethoddefget_type_info(cls):"""获取类型信息"""returnf"形状类型: {cls.__name__}"classCircle(Shape):def__init__(self, radius=1): self.radius = radius @classmethoddefcreate_default(cls):"""Circle类的默认创建方法"""return cls(radius=1) # 默认半径为1classRectangle(Shape):def__init__(self, width=1, height=1): self.width = width self.height = height @classmethoddefcreate_default(cls):"""Rectangle类的默认创建方法"""return cls(width=1, height=1) # 默认宽高为1# 多态行为演示shapes = [Circle, Rectangle]for shape_class in shapes:# 每个类有自己的create_default实现 shape = shape_class.create_default() print(f"{shape_class.__name__}: {shape_class.get_type_info()}") print(f"创建的默认对象: {shape.__dict__}")
4. 应用示例
4.1 数据库模型示例
classUser: users_db = [] # 模拟数据库def__init__(self, username, email, role="user"): self.username = username self.email = email self.role = role @classmethoddefcreate_user(cls, username, email, role="user"):"""创建用户并保存到数据库"""# 验证逻辑if cls.find_by_username(username):raise ValueError(f"用户名 {username} 已存在")# 创建用户 user = cls(username, email, role) cls.users_db.append(user)return user @classmethoddeffind_by_username(cls, username):"""根据用户名查找用户"""for user in cls.users_db:if user.username == username:return userreturnNone @classmethoddefget_users_by_role(cls, role):"""根据角色获取用户列表"""return [user for user in cls.users_db if user.role == role] @classmethoddefget_statistics(cls):"""获取用户统计信息""" total = len(cls.users_db) roles = {}for user in cls.users_db: roles[user.role] = roles.get(user.role, 0) + 1return {"total_users": total,"by_role": roles }# 使用示例admin = User.create_user("admin", "admin@example.com", "admin")user1 = User.create_user("user1", "user1@example.com")user2 = User.create_user("user2", "user2@example.com")print(f"查找用户: {User.find_by_username('admin').email}")print(f"所有用户: {User.get_statistics()}")
4.2 配置文件管理示例
import jsonclassAppConfig: _config = {"version": "1.0.0","debug": False,"max_connections": 100 } @classmethoddefload_from_file(cls, filename):"""从文件加载配置"""with open(filename, 'r') as f: cls._config.update(json.load(f)) print(f"配置已从 {filename} 加载") @classmethoddefsave_to_file(cls, filename):"""保存配置到文件"""with open(filename, 'w') as f: json.dump(cls._config, f, indent=2) print(f"配置已保存到 {filename}") @classmethoddefget(cls, key, default=None):"""获取配置项"""return cls._config.get(key, default) @classmethoddefset(cls, key, value):"""设置配置项""" cls._config[key] = value @classmethoddefshow_all(cls):"""显示所有配置""" print("当前配置:")for key, value in cls._config.items(): print(f" {key}: {value}")# 使用示例AppConfig.show_all()# 修改配置AppConfig.set("debug", True)AppConfig.set("timeout", 30)# 保存和加载配置AppConfig.save_to_file("config.json")# AppConfig.load_from_file("config.json") # 从文件加载AppConfig.show_all()
4.3 缓存机制实现示例
from functools import lru_cacheimport timeclassDataProcessor: _cache = {}def__init__(self, data): self.data = data @classmethoddefprocess_with_cache(cls, data_id, data):"""带缓存的处理方法"""if data_id in cls._cache: print(f"从缓存获取数据: {data_id}")return cls._cache[data_id] print(f"处理新数据: {data_id}")# 模拟耗时处理 time.sleep(0.5) processor = cls(data) result = processor._complex_processing()# 缓存结果 cls._cache[data_id] = resultreturn result @classmethoddefclear_cache(cls):"""清空缓存""" cls._cache.clear() print("缓存已清空") @classmethoddefget_cache_info(cls):"""获取缓存信息"""return {"cached_items": len(cls._cache),"cache_keys": list(cls._cache.keys()) }def_complex_processing(self):"""复杂的处理逻辑"""returnf"处理结果: {self.data.upper()}"# 使用示例print("第一次处理:")result1 = DataProcessor.process_with_cache("data1", "hello")print(result1)print("\n第二次处理相同数据:")result2 = DataProcessor.process_with_cache("data1", "hello") # 从缓存获取print(result2)print("\n处理新数据:")result3 = DataProcessor.process_with_cache("data2", "world")print(result3)print(f"\n缓存信息: {DataProcessor.get_cache_info()}")DataProcessor.clear_cache()print(f"清空后缓存信息: {DataProcessor.get_cache_info()}")
5. 类方法与静态方法的对比
classCalculator: @staticmethoddefadd(a, b):"""静态方法:不访问类或实例的任何属性"""return a + b @classmethoddefoperation_count(cls):"""类方法:可以访问和修改类属性"""ifnot hasattr(cls, '_count'): cls._count = 0 cls._count += 1return cls._count @classmethoddefadd_with_count(cls, a, b):"""类方法:结合业务逻辑和类状态""" count = cls.operation_count() result = cls.add(a, b) # 调用静态方法 print(f"操作 #{count}: {a} + {b} = {result}")return result# 使用对比print(f"静态方法: {Calculator.add(5, 3)}")print(f"类方法计数: {Calculator.operation_count()}")print(f"带计数的加法: {Calculator.add_with_count(10, 20)}")print(f"总操作次数: {Calculator.operation_count()}")
6. 其他用法
6.1 链式调用
classQueryBuilder:def__init__(self): self.query = "" @classmethoddefselect(cls, *columns):"""创建SELECT查询""" builder = cls() columns_str = ", ".join(columns) if columns else"*" builder.query = f"SELECT {columns_str}"return builderdeffrom_table(self, table):"""添加FROM子句""" self.query += f" FROM {table}"return selfdefwhere(self, condition):"""添加WHERE子句""" self.query += f" WHERE {condition}"return selfdefbuild(self):"""构建完整查询"""return self.query# 链式调用示例query = QueryBuilder.select("id", "name", "email") \ .from_table("users") \ .where("age > 18") \ .build()print(f"生成的SQL: {query}")
6.2 单例模式实现
classSingleton: _instance = Nonedef__init__(self, name): self.name = name @classmethoddefget_instance(cls, name="Default"):"""获取单例实例"""if cls._instance isNone: print(f"创建新实例: {name}") cls._instance = cls(name)else: print(f"返回现有实例: {cls._instance.name}")return cls._instance# 测试单例模式singleton1 = Singleton.get_instance("First")singleton2 = Singleton.get_instance("Second") # 不会创建新实例print(f"singleton1 is singleton2: {singleton1 is singleton2}")print(f"实例名称: {singleton1.name}")
7. 试一试
7.1 练习题
7.2 参考答案
# 练习题1参考答案classProduct: products = []def__init__(self, name, category, price): self.name = name self.category = category self.price = price @classmethoddeffrom_csv(cls, csv_string):"""从CSV字符串创建产品""" name, category, price = csv_string.split(',')return cls(name.strip(), category.strip(), float(price.strip())) @classmethoddeffrom_dict(cls, data):"""从字典创建产品"""return cls(data['name'], data['category'], data['price']) @classmethoddefget_category_stats(cls):"""获取类别统计""" stats = {}for product in cls.products: stats[product.category] = stats.get(product.category, 0) + 1return statsdefsave(self):"""保存产品""" self.products.append(self)return self# 练习题2参考答案classLogger: _logs = [] _level = "INFO" _levels = ["DEBUG", "INFO", "WARNING", "ERROR"] @classmethoddefset_level(cls, level):"""设置日志级别"""if level in cls._levels: cls._level = level cls.log(f"日志级别设置为: {level}", "INFO")else:raise ValueError(f"无效的日志级别。可选: {cls._levels}") @classmethoddeflog(cls, message, level="INFO"):"""记录日志"""if cls._levels.index(level) >= cls._levels.index(cls._level): log_entry = {"timestamp": time.time(),"level": level,"message": message } cls._logs.append(log_entry) print(f"[{level}] {message}") @classmethoddefget_stats(cls):"""获取日志统计""" stats = {}for log in cls._logs: stats[log['level']] = stats.get(log['level'], 0) + 1return {"total": len(cls._logs),"by_level": stats,"current_level": cls._level } @classmethoddefclear_logs(cls):"""清空日志""" cls._logs.clear() cls.log("所有日志已清空", "INFO")
8. 总结
8.1 何时使用@classmethod
8.2 注意事项
通过掌握@classmethod,可以编写更加灵活、可维护的面向对象代码,特别是在需要处理类级别状态或提供多种对象创建方式时。