调皮用法|python语言中的self参数
【1】引言
最近做故障分析的过程中,使用了python语言中的self参数,真实十分地灵活且调皮,今天就记录下来,和大家一起学习。
【2】self参数
self参数最大的好处是,可以在随时随地体现自己,但是有一个前提:必须将self定义为第一个参数。
【2.1】参数定义
先给出一个示例:
class SelfTester:def __init__(self, value):# 初始化实例属性self.value = valueprint(f"创建实例,value = {self.value}")
在这里先定义了一个类(class):SelfTester,然后再类的内部定义了一个函数_init_,函数的第一个参数就是self。
这是一种约定俗成的写法,所以按照这个方法写就可以了。
注意到_init_(self,value)的第二个参数是value,要想给value赋值,直接使用self.value=value。从赋值的操作来看,selfg更像是一个取地址的操作,给形式的value所在的地址赋值了一个实质的值。
然后继续看:
def get_value(self):# 访问实例属性return self.valuedef increment(self, amount):# 修改实例属性self.value += amountprint(f"增加值: {amount},新值 = {self.value}")def call_another_method(self):# 在一个方法中调用另一个方法current = self.get_value()print(f"当前值: {current}")self.increment(5)
在子函数get_value(self)中,可以理解为将self这个地址存储的value值取出来;
在子函数increment(self, amount)中,给self这个地址存储的value值增加了一个amount;
在子函数call_another_method(self)中,使用了两个操作:
第一个是用self调用get_value()函数,调用的值赋给current;
第二个是用self调用increment()函数,给increment()函数的amount赋值5,但需要注意的是,这里只需要写一个参数。
根据上述子函数,尤其是最后一个,明显感受到self非常的灵活,如果没有其他参数,它就是参数,比如get_value(self),如果有其它参数,它就可以省略,比如self.increment(5)。
【2.2】实例引入
然后给出具体的实例值:
# 创建两个独立的实例
a = SelfTester(10) # 输出: 创建实例,value = 10
b = SelfTester(20) # 输出: 创建实例,value = 20# 访问属性
print(f"实例 a 的值: {a.get_value()}") # 输出: 实例 a 的值: 10
print(f"实例 b 的值: {b.get_value()}") # 输出: 实例 b 的值: 20# 修改属性
a.increment(3) # 输出: 增加值: 3,新值 = 13
b.increment(7) # 输出: 增加值: 7,新值 = 27
这里有两种调用self的方法:
第一种是通过具体的实例名a和b的直接赋值,给实例约定了10和20两个值,这两个值通过self指向的地址存储起来,然后直接调用get_value()函数,就可以取出这两个值。
第二种是用示例名称a和b直接调用increment()函数,将示例的值分别增加3和7。
这两种调用方法中,都没有直接出现self,这是因为self这个地址存储的实例就是a和b,所以不需要self再出现了。
【2.3】调用其他方法
继续看代码:
# 方法间调用
a.call_another_method()
# 输出:
# 当前值: 13
# 增加值: 5,新值 = 18# 验证实例间独立性
print(f"实例 a 的最终值: {a.get_value()}") # 输出: 实例 a 的最终值: 18
print(f"实例 b 的最终值: {b.get_value()}") # 输出: 实例 b 的最终值: 27
调用其他方法是一个函数:call_another_method()。在这个函数中,会先直接取值,然后再给值增加5。
a已经是实例,所以它可以直接使用call_another_method()中的所有内容。
由于b没有调用call_another_method()函数,所以b的值不会变。
整个代码运行后的输出为:
创建实例,value = 10
创建实例,value = 20
实例 a 的值: 10
实例 b 的值: 20
增加值: 3,新值 = 13
增加值: 7,新值 = 27
当前值: 13
增加值: 5,新值 = 18
实例 a 的最终值: 18
实例 b 的最终值: 27
此时的完整代码为:
class SelfTester:def __init__(self, value):# 初始化实例属性self.value = valueprint(f"创建实例,value = {self.value}")def get_value(self):# 访问实例属性return self.valuedef increment(self, amount):# 修改实例属性self.value += amountprint(f"增加值: {amount},新值 = {self.value}")def call_another_method(self):# 在一个方法中调用另一个方法current = self.get_value()print(f"当前值: {current}")self.increment(5)# 创建两个独立的实例
a = SelfTester(10) # 输出: 创建实例,value = 10
b = SelfTester(20) # 输出: 创建实例,value = 20# 访问属性
print(f"实例 a 的值: {a.get_value()}") # 输出: 实例 a 的值: 10
print(f"实例 b 的值: {b.get_value()}") # 输出: 实例 b 的值: 20# 修改属性
a.increment(3) # 输出: 增加值: 3,新值 = 13
b.increment(7) # 输出: 增加值: 7,新值 = 27# 方法间调用
a.call_another_method()
# 输出:
# 当前值: 13
# 增加值: 5,新值 = 18# 验证实例间独立性
print(f"实例 a 的最终值: {a.get_value()}") # 输出: 实例 a 的最终值: 18
print(f"实例 b 的最终值: {b.get_value()}") # 输出: 实例 b 的最终值: 27
综上所述,可以理解为,self是一个地址形参,一旦有具体的实例名后,这个实例名就存储在self这个地址里面,此后实力名的操作在类内部(class)是完全自由的。
【3】其他说明
实际上,self是一个约定俗成的写法,也是一个约定俗成的字符,把代码里面的self换成其他非python定义的关键字,得到的效果是一样的,比如self换成sf后也是上面的结果。