Discuss / Python / 好乱。。。

好乱。。。

Topic source

even林0

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

第一,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之间是又很大区别的.为什么有这种区别希望有大神解释一下

测试一: 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只是限制实例新增未定义的属性而不会限制类本身和继承类。

御蓝破

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

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调用过了。

沉幕西凉

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

感觉你第二部分理解是错的,MethodType把方法绑定到类的用法,实际上并不是将这个方法直接写到Stu类内部,而是在Stu内存中创建一个link指向外部的方法,在创建Stu实例的时候这个link也会被复制。,如果是用上文中廖老师绑定方法到类的用法

Stu.set_age=set_age

则得到的结果不会覆盖。

Leaving_Top

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

我是这么理解的...

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

我按照张教主的代码原样打了一遍,发现最后的两行也就是调用set_city方法和输出a.city的时候,编辑器会报错,但是控制台上还是输出了应有的内容

kds0714

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

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

C1AY丶

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

但是直接把方法写入类里面,再通过调用方法依次赋值,并不会把原先的值覆盖了。 好像只是通过类绑定的方法,值才会被覆盖。

ziranzizai0

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

先说结论: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

以上


Reply