Discuss / Python / 为什么通过动态绑定类的实例方法,不能修改实例属性?

为什么通过动态绑定类的实例方法,不能修改实例属性?

Topic source
from types import MethodType


class Student(object):
    def __init__(self, *args, **kwargs):
        self.name = kwargs.pop('name')
        self.age = kwargs.pop('age')
        self.score = kwargs.pop('score')


def set_score(self, value):
    self.score = value


def get_score(self):
    return self.score


Student.set_score = MethodType(set_score, Student)
Student.get_score = MethodType(get_score, Student)
t = Student(name="Bryan", age=24, score=80)
# 输出80
print(t.score)
t.set_score(100)
# 输出100
print(t.get_score())
# 为什么这里还是输出80,而不是100?
print(t.score)


HellPlay

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

我实验了一下分别利用 t.scoret.set_score() 赋值,用 t.score 和 t.get_score() 获取结果,结果显示:

 t.scoret.set_score() 赋值互不影响, t.score的改变不会影响 t.get_score() 结果, t.set_score() 赋值不改变 t.score 结果

-水墨青

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

因为给一个实例绑定的方法,不会影响另一个实例。你代码里实际上是新建了一个和Student类同名的Student实例,然后给它进行动态绑定。t实例是Student类的另一个实例,不受影响。

你把方法绑到类中去了,虽然你感觉修改的是实例,但是实际上修改的是类,不信你可以print(Student.score),出来的就是100

Aimee_300

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

因为属性和方法是不一样的。属性是变量,方法是函数,但是由于变量也可以是函数,因此具有迷惑性。区别方法是调用方法时不需要给self传参,而调用函数属性时则需要。

利用MethodType添加的是方法,Student是定义的类,同时也是type类的实例(python中类也是对象),因此你实际上给Student这一type类的实例添加了方法set_score。但是,只有给Student添加属性,才能给Student的实例添加方法,因此要用Student.set_score=set_score来给Student的实例添加方法。

Student.set_score = MethodType(set_score, Student)
Student.get_score = MethodType(get_score, Student)

没见过这种写法啊,如果这种写法作用真如他们说的那样:为类绑定了一个方法。那么同时也会为类新增一个score属性。

而实例也有score属性,实力的属性优先级要高于类,当用类调用score属性时,即Student.score,就会打印100.当用实例调用score属性时就会打印80.

SPqvq

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

看不懂前面的解释,但是可以试并且猜一下是MethodType的问题:

因为`MethodType(f, x)`的第二个参数x,实际就是以后执行 f 时代入的self。

比如:

from types import MethodType
class Student:
  pass

A=Student()
B=Student()

def f(self, x):
  self.x = x

B.f = MethodType(f, A)
B.f(555)

print(A.x) # 555
print(B.x) # AttributeError: 'Student' object has no attribute 'x'

此时调用 B.f(555),等价于运行 f(A, 555),即 A.x = 555,但B本身依旧没有x

类也同理

def set_score(self, score):
  self.score = score

Student.set_score = MethodType(set_score, Student)

A.score = 80
A.set_score(50)

print(A.score) # 80
print(Student.score) # 50

确实是弄了个类方法,但调用A.set_score(50),等价于运行 set_score(Student, 50),即 Student.score = 50,对A没有影响,影响的是Student本身的类属性

dalao 牛逼!!!!! 我终于懂了

我悟了

问题在这里:

Student.set_score = MethodType(set_score, Student)
Student.get_score = MethodType(get_score, Student)

改这样就没问题了:

Student.set_score = set_score
Student.get_score = get_score

  • 1
  • 2

Reply