Discuss / Python / 关于MethodType和setattr以及直接用等号赋值的区别

关于MethodType和setattr以及直接用等号赋值的区别

Topic source

一盒噪噪

#1 Created at ... [Delete] [Delete and Lock User]

(已经理解了原因的,可以不看验证了)

,问题:为什么用MethodType方法,当一个类对象A调用绑定方法,更改其中的变量时,另一个类对象B中的此变量也会随之更改

        答案:此时调用函数a时,传入的self是类名,而不是类对象,函数a中前跟‘self.’的变量名属于静态变量,为所有类对象共有

验证:

def a(self,age):
	self.m=age
	print(self)        #查看每次调用函数a时,传入的self是什么
class Q:
    pass

PS(给前几章学的不好的同学看,已经学会的可略过)我们由前几章可知:更改class中的静态变量,所有类对象中的此变量都会改变。

因为静态变量单独存放在一个内存空间中,创建类对象的时候不再复制此内存空间,而是共用一个内存空间。

而每个类对象都有一个单独的变量存储空间,且名称==类对象的名称,所以更改类对象中特有的变量,与其他内存空间中的同名变量无关

from types import MethodType
Q.a=MethodType(a,Q)

w=Q()
w.a(1)      #此时输出:<class '__main__.q'>

i=Q()
i.a(2)      #此时输出:<class '__main__.q'>

可得:用MethodType方法,传入a中的是类名,而不是类对象的名称             所以函数a中创建的变量,存放在类对象的存储空间中         

!所以调用Q中的函数a改变的是类对象共有的静态变量

对比一下:直接用等号赋值的方法(用setattr方法和等号赋值方法的作用相同,你可以试一下)

Q.b=a
w.b(10)    #此时输出:<__main__.q object at 0x000002CE722CFE10>

w.i(20)    #此时输出:<__main__.q object at 0x000002CE72305748>

ps插播一条新闻:0x000002CE72305748   指的类对象w的地址(16进制形式)

二、问题:MethodType和setattr/'='的区别(setattr和直接赋值相同,后面只写setattr的作用)

        答案:setattr函数在类Q中创建了一个变量名Q.a,

                                           直接指向函数a,也就是说Q.a和a是同一个函数(不存在复制或者作用相同,它们就是同一个)        Q.a is a  (True)

                    MethodType在Q中创建的变量Q.b则不同,

                                          它指向一个Q的绑定方法,这个绑定函数指向a     Q.b和a并不是同一个函数 , 也不是a的复制  (甚至Q.b根本不是函数,是一个方法)   Q.b != a   (True)

                                          用MethodType方法创建的相当于一个字典,{key: value}   key是Q.b   value是a

验证:(连接上面的代码)

id(a)        #3085702665488
id(Q.a)      #3085702665488
id(Q.b)      #3085699975368

Q.a is a     #True
Q.b is a     #False
Q.b == a     #False

可得:用setattr方法创建的Q.a是a,用MethodType方法创建的Q.b不是a

题外话:我看大家都很纠结MethodType到底有什么用,好像它的功能可以用=或者setattr完成,我觉得python作为一门能少则少的语言,创建者一定不会写多余无用的方法出来,

比如说我上面举的一个它们作用的不同之处,MethodType一定还有别的很多特点,用别的方法取代不了的作用,有时候了解了源码才能更好的掌握、使用它,后面学习了新的知识,也一定会发现它别的用处,不用在现在就纠结它有啥子用,就像你学微积分的时候可能不知道它能干什么,毕竟买菜也用不着微积分

一盒噪噪

#2 Created at ... [Delete] [Delete and Lock User]

以上我写的并不准确,只是帮助大家理解(不要深究啊~)

拓展:在类中定义的函数或方法,每次创建类对象的时候,都会被复制一次,调用的时候实际上调用的并不是同一个函数

用等号赋值或者setattr方法,也是一样的,不同的类对象调用的也不是同一个函数

而用MethodType方法,是在类中建立了一个和外部函数的联系,每次创建类对象,都会把这个联系(方法)复制一次,调用的时候其实是调用的同一个函数

诶第一条说‘调用函数a时,传入的self是类名,而不是类对象’,因为你这里是直接用MethodType对class进行方法绑定了,之后再用实例去调用类方法调用的就是一个函数。

如果把类对象分开进行方法绑定,就算绑定的是一个方法,之间也是不影响的。

from types import MethodTypedef set_age(self,age):    self.age=ageclass Student():    pass
s1=Student()s1.s_age=MethodType(set_age,s1)s1.s_age(33)s0=Student()s0.s_age=MethodType(set_age,s0)s0.s_age(44)print(s1.age)

33

Process finished with exit code 0

为什么我打出来的字是红色的o(╥﹏╥)o


  • 1

Reply