好乱。。。
Topic source测试一: class MyClass: slots=('name','age','set_score') pass
a=MyClass() a.score=100
Traceback (most recent call last): File "<pyshell#6>", line 1, in <module> a.score=100 AttributeError: 'MyClass' object has no attribute 'score'
直接给实例a添加score属性提示属性不存在,因为slots中未定义。
测试二: def set_score(self, score): self.score=score
from types import MethodType MyClass.set_score = MethodType(set_score, MyClass)
a = MyClass () a. set_score (100) a.score #返回结果100
上段测试代码中,表面上实例a看通过函数突破了slots对实例属性的限制,增加了score属性,但实际并非如此,继续如下测试:
a.name='cc' a.name is MyClass.name#返回False
a.score is MyClass.score返回True
del a.score Traceback (most recent call last): File "<pyshell#32>", line 1, in <module> del a.score AttributeError: 'MyClass' object attribute 'score' is read-only
通过is判断,可以看出实例a和类MyClass的name属性不是同一个对象。而实例a和类MyClass的score属性实际是同一个对象。再通过del删除实例a的score属性的返回可以看出a.score实际就是引用的类MyClass属性。
结论:导致这一现象的原因为MethodType方法是针对指定实例新增函数。通过此方法在类上新增函数时,实例使用此方法实际就是引用类的方法修改类属性,即直接在类上新增属性。并非突破了实例新增属性的限制。Slots只是限制实例新增未定义的属性而不会限制类本身和继承类。
Stu类本身并没有属性和方法,所以用这个类创建的实例也没有属性和方法。用MethodType将set_age方法绑定到Stu类,并不是将这个方法直接写到Stu类内部,而是在Stu内存中创建一个link指向外部的方法,在创建Stu实例的时候这个link也会被复制。所以不管创建多少实例,这些实例和Stu类都指向同一个set_age方法。A.set_age(10)并没有在A这个实例内部创建age属性,而是将age属性创建在外部set_age方法的内存区中。因为A和B内部link都指向外部set_age方法的内存区,所以不管A还是B在调用set_age方法的时候改变的是set_age方法内存区里的age属性,所以A改了B也就改了,如果新建一个实例C在没有调用set_age方法的前提下也会有age属性,因为C的link指向的set_age方法的内存区,而set_age之前被A或者B调用过了。
感觉你第二部分理解是错的,MethodType把方法绑定到类的用法,实际上并不是将这个方法直接写到Stu类内部,而是在Stu内存中创建一个link指向外部的方法,在创建Stu实例的时候这个link也会被复制。,如果是用上文中廖老师绑定方法到类的用法
Stu.set_age=set_age
则得到的结果不会覆盖。
我是这么理解的...
class A(object):
def __init__(self,name):
self.name = name
def get_name(self):
print(self.name)
def set_name(self,name):
self.name = name
from types import MethodType
A.set_name = MethodType(set_name,A) #set_name可以看做是类方法
a1 = A('a1')
print(a1.name)
a1.set_name('A1') # a1作为实例调用set_name时,因为self.name 原来是在__ init__方法下,因此属于实例属性,而后来添加的类方法本身并不在A类中,是后来绑定的,因此同名的name,被看做了 类属性,因此,这个就转变成了实例属性 和类属性的问题了
print A.name # 输出为 A1
print a1.name # 输出为 a1
del a1.name
print a1.name #输出为 A1
Student.set_city = MethodType(set_city, Student)
我的理解:这是为Student绑定set_city方法,该方法可以被所有实例调用,set_city方法的实现中,语句:self.city=city,表示为Student绑定city变量。
a = Student() a.set_city(Beijing) a.city
所以,语句:a.city,其实就是实例a访问了Student的city属性。
直接用Student.set_age=set_age语句就不是那种结果了为什么 class Student(object): pass
s=Student() a=Student() Student.set_age=set_age s.set_age(9) a.set_age(10) print(s.age,a.age) 9 10
先说结论:slots可以严格限制实例属性的添加。
其实廖老师正文里开头就说明了:
但是,如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性。 为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class实例能添加的属性:
此处需注意,我们已经知道属性分为实例属性和类属性,但slots限制的只有实例属性。 如下给类绑定方法后,通过实例操作的是类属性。也就是说,slots明明限制的是实例属性,但你通过实例操作类属性,slots很委屈的,好吗?
from types import MethodType
Stu.set_age=MethodType(set_age,Stu) //给类绑定方法
a.set_age(15) \\通过set_age方法,设置类属性age的值。*此处并没有操作实例属性*
s.set_age(11) \\也是设置类属性age
print(s.age,a.age) \\由于a和s自身没有age属性,所以打印的是类属性age的值
如果我们将方法绑定到实例上,能看得清楚一点。
from types import MethodType
def set_city(self, city):
self.city=city
class Student(object):
__slots__ = ('name', 'set_city')
pass
a = Student()
a.set_city = MethodType(set_city, a)
a.set_city("Dalian")
Traceback (most recent call last):
File "C:/pytest/test.py", line 15, in <module>
a.set_city("Dalian")
File "C:/pytest/test.py", line 5, in set_city
self.city=city
AttributeError: 'Student' object has no attribute 'city'
另外:使用MethodType时,如果绑定的是类则方法操作的是类属性,绑定的是实例则方法操作的是实例属性。
class A(object):
def init(self,name):
self.name = name
def get_name(self):
print(self.name)
def set_name(self,name):
self.name = name
from types import MethodType
a1 = A('a1')
A.set_name = MethodType(set_name,A) //此处将A->a1,则最终打印出A1
print(a1.name) #result: a1
a1.set_name('A1')
print(a1.name) #result: a1 这里不明白为啥还是打印出a1
以上
even林0
第一,slots只能限制添加属性,不能限制通过添加方法来添加属性: 错误! slots限制的实例属性,不包括类属性.
def set_city(self, city): self.city=city
class Student(object): slots = ('name', 'age', 'set_city') pass
Student.set_city = MethodType(set_city, Student) 此处应使用Student.set_city = set_city,这样当a.set_city(Beijing)调用时改的才是实例属性city,否则设置的其实是类属性的city.原因我不知道,但我做了实验确实如此.希望大神能解释一下
a = Student() a.set_city(Beijing) a.city
第二,属性分实例属性和类属性,多个实例同时更改类属性,值是最后更改的一个. 正确!
第三, 不能随便用a.set_age()更改age的值(因为调用此方法更改的是类属性age的值,不是实例a自身的age属性值) 不正确! 如果set_age()方法是在类里面定义的或者是通过类属性直接赋值(如上面的Student.set_city = set_city),那么用a.set_age()更改的是实例对象a的属性,而不是类属性.
综上所述,造成你混乱的其实是因为Student.set_city = MethodType(set_city, Student)和Student.set_city = set_city之间是又很大区别的.为什么有这种区别希望有大神解释一下