实例方法
在类中定义的方法默认都是实例方法,前面几篇文章已经大量使用到实例方法
实例方法栗子
class PoloBlog: def __init__(self, name, age): print("自动调用构造方法") self.name = name self.age = age def test(self): print("一个实例方法,需要通过对象调用") print("my name is :", self.name, " and my age is :", self.age) blog = PoloBlog("小菠萝", 24) blog.test() # 输出结果 自动调用构造方法 一个实例方法,需要通过对象调用 my name is : 小菠萝 and my age is : 24
- 最少也要包含一个 self 参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)
- 实例方法通常会用实例对象直接调用
通过类名调用实例方法
Python 也支持通过类名调用实例方法,但需要手动给 self 参数传实例对象
blog = PoloBlog("小菠萝", 24) PoloBlog.test(blog) # 输出结果 自动调用构造方法 一个实例方法,需要通过对象调用 my name is : 小菠萝 and my age is : 24
假设不传实例对象,pycharm 会有warning
类方法
类方法和实例方法很相似,又很不相似
相似点
- 也至少要包含一个参数,不过通常命名为 cls
- 在调用类方法时,无需显式为 cls 参数传参,但传递的并不是实例对象,而是类对象本身
不同点
最大的不同在于需要使用 @classmethod 装饰器才能称为类方法
实际栗子
class PoloBlog: # 类属性 sum = 0 # 类方法, 添加装饰器 @classmethod def class_func(cls): print("class_func cls 对象的 id ", id(cls)) cls.sum += 1 print("类属性 sum ", cls.sum) @classmethod def class_func_twi(cls): print("class_func_twi cls 对象的 id ", id(cls)) cls.sum += 1 print("类属性 sum ", cls.sum) PoloBlog.class_func() PoloBlog.class_func_twi() # 输出结果 class_func cls 对象的 id 140583542774880 类属性 sum 1 class_func_twi cls 对象的 id 140583542774880 类属性 sum 2
cls 代表的是同一个对象,类对象
类方法可以调用实例方法吗?
可以,但有局限性
class PoloBlog: # 类属性 sum = 0 def __init__(self, sum): self.sum = sum # 实例方法 def test(self): print("self id is ",id(self)) print("self 对象的 sum 属性值为:", self.sum) # 类方法, 添加装饰器 @classmethod def class_func(cls): print("cls id is ", id(cls)) print("类属性 sum ", cls.sum) # 调用实例方法 cls.test(cls) PoloBlog.class_func() # 输出结果 cls id is 140500501817184 类属性 sum 0 self id is 140500501817184 self 对象的 sum 属性值为: 0
- 类方法调用实例方法的方式: cls.实例方法(cls) ,通过 cls 调用,且还要传递 cls 为参数
- 从 id 相同即可看出,实例方法接收的仍然是一个类对象
实例对象可以调用类方法吗?
可以,但不建议
blog = PoloBlog(2) blog.class_func() # 输出结果 cls id is 140500501817184 类属性 sum 0 self id is 140500501817184 self 对象的 sum 属性值为: 0
- blog 是一个实例对象,且初始化赋值了 sum 实例属性
- 但最后实例方法打印的仍然是 sum 类属性,表明类方法无法访问实例属性
- 且 cls、self 参数的 id 和上面的栗子完全一样,表明即使通过实例对象调用类方法,传递的仍然是类对象的引用,所有类方法都被同一个类对象调用,一个类只有一个类对象
实例方法可以调用类属性吗?
可以,但不能通过实例对象调用,只能通过类对象
class PoloBlog: # 类属性 name = "类啊类属性" def __init__(self, name): self.name = name # 实例方法 def test(self): # 错误栗子 # print(name) # 访问的仍然是实例属性 print(self.name) # 通过类名访问 print(PoloBlog.name) blog = PoloBlog("小菠萝") blog.test() # 输出结果 小菠萝 类啊类属性
假设直接调用 name 变量可以吗
肯定不行,报错
扩展思考题!
- 一个方法内部既需要访问实例属性,又需要访问类属性,应该定义为什么方法?
- 答案:实例方法,因为可以通过 类对象.类属性 来访问,但在类方法中无法访问实例属性
代码栗子直接看上面一个就是啦!
静态方法
- 和之前学过的函数一毛一样,唯一区别是:静态方法需要定义在类体中,且需要添加 @staticmethod 装饰器
- 静态方法没有 self、cls 参数,也不需要至少传一个参数,和普通函数一样
- Python 解释器不会对它包含的参数做任何类或对象的绑定,所以静态方法无法调用任何类属性、类方法、实例属性、实例方法,除非通过类名和实例对象
什么时候会用静态方法
类里面封装的方法
- 既不需要访问实例属性、实例方法
- 也不需要访问类属性、类方法
就可以考虑将这个方法封装成一个静态方法
实际栗子
class PoloBlog: # 静态方法 @staticmethod def info(name, age): print(name, age) # 通过类对象调用 PoloBlog.info("小菠萝111", 24) blog = PoloBlog() # 通过实例对象调用 blog.info("小菠萝222", 14) # 输出结果 小菠萝111 24 小菠萝222 14
关于实例方法、 classmethod 和 staticmethod 的实际应用
场景
简单来说
- 实例方法:方法内部需要访问实例属性、实例方法就定义为实例方法;既需要访问实例属性、方法,也需要访问类属性、方法,那必须定义为实例方法
- 类方法:方法内部只需要访问类属性、类方法就定义为类方法
- 静态方法:方法内部既不需要访问实例属性、实例方法,也不需要访问类属性、类方法就定义为静态方法
也可以参考这篇文章
待我实战后再来完善此章节