Python类中方法种类介绍
Python类中方法种类介绍
类方法的种类及说明:
| 方法类型 | 说明/描述 |
| 1.实例方法 | 1).无特定装饰器,第一个参数为 “self”(指向实例对象)。 2).可通过“self.属性名” 访问实例属性,也可通过“self.__class__.属性名”或“类名.属性名”访问类属性。 3).应通过 “实例.方法名()” 方式调用;使用“类名.方法名()”需手动传入实例self,不推荐。 |
| 2.类方法 | 1). 使用“@classmethod”装饰,第一个参数为“cls”(指向类本身)。 2).可通过“cls.属性名” 访问类属性;无法直接访问实例属性(因不绑定具体实例)。 3).可通过“类.方法名()”或“实例.方法名()” 调用,两种方式均自动传递“cls”参数。 |
| 3.静态方法 | 1). 使用 “@staticmethod”装饰,无强制参数(不绑定“cls” 或“self”)。 2).通常不访问类或实例属性;如需访问类属性,可通过“类名.属性名”,但不符合静态方法设计初衷。 3).可通过“类.方法名()”或“实例.方法名()”调用,无参数自动传递。 |
| 4.抽象方法 | 1. 使用 `@abstractmethod` 装饰,必须定义在继承自 `abc.ABC` 的抽象基类中。 2.必须由子类实现,否则子类无法实例化。 3.可为实例方法(参数“self”)或类方法(参数“cls”),具体由子类实现决定。 |
| 5.魔术方法 | 1).以双下划线开头和结尾(如“__init__”、“__str__”)。 2).由 Python 解释器自动调用,用于实现对象的初始化、表示、运算等底层行为。 3).不应手动直接调用,而应通过相应内置函数或操作符触发。 |
| 6.特性方法 | 1).使用“@property”装饰,将方法转换为“只读属性”。 2).调用时无需括号,如 “obj.属性”。 3).可配合“@属性名.setter”和“@属性名.deleter”定义设置和删除逻辑,实现对属性的封装与控制。 |
下面给出示例解释
1.实例方法示例
class Student:class_attr = "学生类" # 类属性(所有实例共享)def __init__(self, name):self.name = name # 实例属性(每个实例独有)def introduce(self): # 实例方法# 可以访问实例属性和类属性print(f"我叫{self.name},属于{self.class_attr}")def get_class_attr(self):# 三种访问类属性的方式(推荐使用前两种)print(f"方式1: {self.__class__.class_attr}") # 通过__class__print(f"方式2: {Student.class_attr}") # 通过类名print(f"方式3: {self.class_attr}") # 通过self(会先在实例中查找)# 调用
stu = Student("小明")
stu.introduce() # 正确调用方式
运行输出:
我叫小明,属于学生类
说明,易错点和注意事项:
1). 忘记写self参数会导致TypeError
错误示例: def introduce(): 缺少self参数
2). 通过类名调用实例方法时必须手动传入实例
正确但繁琐: Student.introduce(stu)
3). self.class_attr 会先在实例属性中查找,找不到才去类属性中查找
如果存在同名的实例属性,可能得到意外结果
2. 类方法示例
class Student:count = 0 # 类属性def __init__(self, name):self.name = nameStudent.count += 1 # 修改类属性@classmethoddef get_count(cls): # 类方法# cls 指向类本身,不是实例return f"学生总数:{cls.count}" # 通过cls访问类属性@classmethoddef from_string(cls, info_str): # 类方法作为工厂方法# 常用于创建实例的替代构造方法name = info_str.split(",")[0]return cls(name) # 相当于调用 Student(name)@classmethoddef try_access_instance_attr(cls):# 这里无法访问实例属性,因为不知道是哪个实例# print(self.name) # 错误!没有self# print(cls.name) # 错误!类没有name属性pass# 调用
stu1 = Student("张三")
stu2 = Student("李四")
print(Student.get_count()) # 通过类调用
print(stu1.get_count()) # 通过实例调用(不推荐)
运行输出:
学生总数:2
学生总数:2
说明,易错点和注意事项:
1). 类方法无法访问实例属性,因为不绑定具体实例
2). 类方法中修改类属性会影响所有实例
3). 通过实例调用类方法虽然可行,但不推荐,容易引起混淆
4). 类方法常用于工厂模式、计数器、类级别配置等场景
3. 静态方法示例
class MathUtils:PI = 3.14159 # 类属性@staticmethoddef add(a, b): # 静态方法# 不接收self或cls参数return a + b@staticmethoddef is_even(number):return number % 2 == 0@staticmethoddef calculate_circle_area(radius):# 虽然可以通过类名访问类属性,但这不符合静态方法的设计初衷# 静态方法应该是纯粹的工具函数,不依赖类状态return MathUtils.PI * radius ** 2 # 不推荐这样做@staticmethoddef bad_practice():# 静态方法中不应该这样做:# print(self.name) # 错误!没有self# print(cls.PI) # 错误!没有clspass# 调用
print(MathUtils.add(5, 3)) # 推荐:通过类调用
util = MathUtils()
print(util.add(2, 2)) # 可行但不推荐:通过实例调用
运行输出:
8
4
说明,易错点和注意事项:
1). 静态方法既不能访问实例属性,也不能直接访问类属性
2). 如果需要访问类属性,应该考虑使用类方法
3). 静态方法应该是无状态的工具函数
4). 通过实例调用静态方法可能让人误解该方法与实例状态有关
4. 抽象方法示例
from abc import ABC, abstractmethodclass Animal(ABC): # 抽象基类def __init__(self, name):self.name = name@abstractmethoddef make_sound(self): # 抽象实例方法# 只有方法定义,没有实现pass@classmethod@abstractmethoddef animal_type(cls): # 抽象类方法# 抽象方法也可以是类方法passdef normal_method(self):# 抽象类中可以包含具体方法return f"{self.name}是动物"class Dog(Animal): # 具体子类def make_sound(self): # 必须实现所有抽象方法return "汪汪!"@classmethoddef animal_type(cls):return "哺乳动物"# 使用
dog = Dog("旺财")
print(dog.make_sound())
运行输出:
汪汪!
说明,易错点和注意事项:
1). 忘记实现抽象方法会导致TypeError
2). 抽象类不能被实例化,只能被继承
3). @abstractmethod必须放在最内层装饰器位置
4). 抽象类中可以包含具体方法,子类可以直接继承使用
5). 抽象方法可以有实现,但通常不提供(通过super()调用)
错误示例:
animal = Animal("抽象动物") TypeError!
5. 魔术方法示例
运行输出:
汪汪!
说明,易错点和注意事项:
1). 忘记实现抽象方法会导致TypeError
2). 抽象类不能被实例化,只能被继承
3). @abstractmethod必须放在最内层装饰器位置
4). 抽象类中可以包含具体方法,子类可以直接继承使用
5). 抽象方法可以有实现,但通常不提供(通过super()调用)
错误示例:
animal = Animal("抽象动物") TypeError!
5. 魔术方法示例
class Book:def __init__(self, title, author, pages=0): # 构造方法# 在对象创建时自动调用self.title = titleself.author = authorself.pages = pagesdef __str__(self): # 字符串表示# 被print()、str()调用return f"《{self.title}》 - {self.author}"def __repr__(self): # 解释器表示# 在交互式环境中显示,被repr()调用return f"Book('{self.title}', '{self.author}')"def __len__(self): # 定义长度# 被len()调用return self.pagesdef __add__(self, other): # 加法运算# 被+操作符调用if isinstance(other, Book):return f"{self.title} & {other.title}"return NotImplementeddef __eq__(self, other): # 相等判断# 被==操作符调用if isinstance(other, Book):return self.title == other.title and self.author == other.authorreturn False# 使用
book1 = Book("Python编程", "John", 300)
book2 = Book("算法导论", "Jane", 500)print(book1) # 自动调用__str__
print(len(book1)) # 自动调用__len__
print(book1 + book2) # 自动调用__add__
print(book1 == book2) # 自动调用__eq__
运行输出:
《Python编程》 - John
300
Python编程 & 算法导论
False
说明,易错点和注意事项:
1). 魔术方法由Python自动调用,不应手动直接调用
2). 不同的魔术方法需要返回特定类型(如__len__返回整数)
3). 运算符重载时应考虑类型检查,对不支持的类型返回NotImplemented
4). 同时实现__str__和__repr__,__repr__应该包含重建对象的信息
5). 某些魔术方法需要成对实现(如__eq__和__ne__)
6. 特性方法示例
class Circle:def __init__(self, radius):# 使用_开头表示受保护的属性self._radius = radiusself._diameter = radius * 2 # 缓存计算值@propertydef radius(self): # 只读属性# 像属性一样访问:circle.radiusreturn self._radius@propertydef area(self): # 计算属性# 每次访问时动态计算return 3.14 * self._radius ** 2@propertydef diameter(self):# 可以返回缓存值以提高性能return self._diameter@diameter.setterdef diameter(self, value): # setter方法# 在赋值时进行验证和计算if value <= 0:raise ValueError("直径必须大于0")self._radius = value / 2self._diameter = value # 更新缓存@radius.deleterdef radius(self): # deleter方法# 定义删除属性时的行为print("删除半径属性")del self._radius# 使用
circle = Circle(5)
print(circle.radius) # 像属性一样访问,无需括号
print(circle.area) # 自动计算
print(circle.diameter) # 使用缓存值circle.diameter = 14 # 通过setter设置,会自动更新radius
print(circle.radius) # 输出: 7# del circle.radius # 会调用deleter方法
运行输出:
5
78.5
10
7.0
说明,易错点和注意事项:
1). @property必须定义在@setter之前
2). setter和deleter的方法名必须与property方法名相同
3). 使用property后,方法调用不需要括号
4). 可以在setter中添加数据验证逻辑
5). 对于计算密集型属性,可以考虑缓存计算结果
6). 避免在property方法中进行耗时操作
附录
Python青少年简明教程:类和对象入门 https://blog.csdn.net/cnds123/article/details/141953553
Python面向对象程序设计讲座 https://blog.csdn.net/cnds123/article/details/108354860
Python中的property介绍 https://blog.csdn.net/cnds123/article/details/129420059
