Discuss / Python / 好乱。。。

好乱。。。

Topic source

鹿与陆

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

这个是通过类方法加上属性,如果是通过实例加方法再加属性是加不上的。

YulWarren

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

@0静悟禅思0

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

a1=A('a1')
print(a1.name) # a1
from types import MethodType
a1.set_name=MethodType(set_name,a1)
a1.set_name('A1')
print(a1.name)  #A1

努云尼尼

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

有关层主这个问题,根据个人想法给出以下答复

公共代码部分,定义class A,定义类外方法set_name,创建A类的实例a1

import functools;
from types import 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

a1 = A('a1');
print(a1);    #刚创建的实例a1,其实例变量name在init后为'a1'

情况一(层主使用的方法):使用MethodType函数将类外方法赋给类A,使用实例a1调用该方法,输出实例变量a1.name


print(hasattr(A,'set_name'));  #此时类A不存在set_name方法
A.set_name = MethodType(set_name,A); #将方法赋给类A
print(hasattr(A,'set_name'));   #此时类A有了set_name方法
print(hasattr(A,'name'));        #此时类A并无类变量name
a1.set_name('A1');        #用类A实例a1调用已绑定的set_name方法
print(hasattr(A,'name')); #此时类A有了类变量name——重要
if hasattr(A,'name'):
    print('类变量A.name为',A.name);
    print('此时实例变量a1.name为',a1.name);
else:
    print('实例变量a1.name为',a1.name);

情况二(层主想要达成的情况):使用MethodType函数将类外方法赋给类A的实例a1,使用实例a1调用该方法,输出实例变量a1.name

print(hasattr(A,'set_name'));  #此时类A不存在set_name方法
A.set_name = MethodType(set_name,a1); #将方法赋给实例a1
print(hasattr(A,'set_name'));   #此时类A有了set_name方法
print(hasattr(A,'name'));        #此时类A并无类变量name
a1.set_name('A1');        #用类A实例a1调用已绑定的set_name方法
print(hasattr(A,'name')); #此时类A没有类变量name——重要
if hasattr(A,'name'):
    print('类变量A.name为',A.name);
    print('此时实例变量a1.name为',a1.name);
else:
    print('实例变量a1.name为',a1.name);

由两种情况的输出和注释可以得知: 1.将操作变量的函数赋给类时,即便使用该类的实例去调用函数,被操作的变量仍然是类变量,实例变量不会有改变,还有增加额外的类变量的风险。 2.如果想要为某个实例增加操作变量的函数,应将该函数赋给对应实例。此时该类的其他实例即使调用该函数进行变量操作,修改的也是函数绑定实例的变量,保证了变量操作的清晰明确。

#续情况一,该类的其他实例调用set_name方法,修改的仍是类变量
a2 = A('a2');
a2.set_name('A2');
if hasattr(A,'name'):
    print('类变量A.name为',A.name); #类变量变为A2
    print('此时实例变量a2.name为',a2.name);    #实例变量仍不变
else:
    print('实例变量a2.name为',a2.name);
#续情况2,该类的其他实例调用set_name方法,修改的仍是a1的变量
a2 = A('a2');
a2.set_name('A2');
if hasattr(A,'name'):
    print('类变量A.name为',A.name);
    print('此时实例变量a2.name为',a2.name);
else:
    print('实例变量a2.name为',a2.name);
    print('实例变量a1.name为',a1.name);

因为你使用a1.set_name的时候实际上还是在执行MethodType(set__name,S)将内容写入了实例,但是根本没执行S.set_name,说到底他只是个写入函数,并不支持执行

lubang03

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

试了一下,slots里面不需要添加'set_city'也可以

class Student(object):
    __slots__ = {'name','age'}在此插入代码

结果是一样的,但是MethodType(set_city,Student)这一句是必须的

Athena_小笛

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

h和你们结论不一样,怎么感觉我用了假python。。

第一个问题,我用 python3.6,是无论如何无法添加slots之外的属性的。

第二个问题,定义了类属性后,dir()每个实例下面是会出现相应属性的。只是单独定义了实例的值之后,实例属性值不会随着class中属性的值改变而改变。

Athena_小笛

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

更正,测试发现用添加类属性的方法的确可以加上实例slots之外的属性,只能用 Student.cha_score = MethodType(set_score,Student) 这种方式, Student.cha_score = set_score 的方式不行。 当然,slot中含有'score'时,两种方式都可以添加属性成功。

Athena_小笛

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

补一句。。测试发现slots只对类的实例的属性起限制作用,对类,子类或父类本身完全无效。实例完全可以通过改变类属性的方法不受限制的添加属性。。

蒙面人mm

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

Student.set_city = MethodType(set_city, Student)

MethodType第二个参数不是只能是实例吗?如果是类,那就是给这个类绑定一个方法吗?然后这个类的所有实例都可以访问了?

蒙面人mm

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

@0静悟禅思0 A所有的属性是:name,get_name,set_name a1所有的属性是:name,get_name 因为set_name绑定的是类,而不是实例

a1 = A('a1') print(a1.name) #result: a1

这里的a1.name=‘a1’

a1.set_name('A1') print(a1.name)

由于a1没有set_name()方法,所以这里是调用的类属性 即执行

A.set_name('A1')

所以此时

A.name='A1'

而a1.name没有被改变,依然是a1 建议打印一条

print(A.name)#结果是A1


Reply