鱼C论坛

 找回密码
 立即注册
查看: 2234|回复: 13

[已解决]第046讲:魔法方法:描述符(Property的原理)中的疑问

[复制链接]
发表于 2021-2-25 16:59:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在46讲的习题中,小甲鱼给出的代码是:
import time

class Record:
    def __init__(self, initval=None, name=None):
        self.val = initval
        self.name = name
        self.filename = "record.txt"

    def __get__(self, instance, owner):
        with open(self.filename, 'a', encoding='utf-8') as f:
            f.write("%s 变量于北京时间 %s 被读取,%s = %s\n" % \
                    (self.name, time.ctime(), self.name, str(self.val)))
        return self.val

    def __set__(self, instance, value):
        filename = "%s_record.txt" % self.name
        with open(self.filename, 'a', encoding='utf-8') as f:
            f.write("%s 变量于北京时间 %s 被修改, %s = %s\n" % \
                    (self.name, time.ctime(), self.name, str(value)))
        self.val = value

有如下一些疑惑:
1. 在运行的时候,是不是也要也要设置某个类,其中该类的有个属性是Record类,也就是
class C:
        x=Record()
2.  filename = "%s_record.txt" % self.name这个语句有什么用?
3.如果:
        c=C()
        c.x=8
        d=C()
  那问什么d.x也是8呢?
4. Record类中的初始化是不是只是在
   Class C:
        x=Record()
  的时候被调用。这样的话,3中的c,d实际上就不能被赋予不同的初始化值。我写这样的代码
  class E:
        def __init__(self,init=None,name=None):
                self.x=Record(init,name)
  然后e=E(100,'china'),那为什么e.x返回的只是对象的地址,而e.x.val才能够返回100.谢谢
       
最佳答案
2021-2-27 19:06:21
Tshirt 发表于 2021-2-27 15:31
谢谢,那么c.x=8中调用了__set__方法,把self.val 设置为8, d.x 这里又调用了__get__方法, 返回了self. ...

c.x and d.x 是同一个对象,即x , 它们返回的都是x.val
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-25 20:24:23 | 显示全部楼层
1,x = Record(), 是类的实例化,x是Record类的实例化对象,如果要使用类的方法,使用类的继承即可
2,filename = 说明是文件名, 这个语句就是设置一个文件名
3,c = C(), c是一个实例化对象,c.x是给这个对象一个属性赋值, d = C(), d是一个实例化对象,虽然继承同一个父类,但是是两个毫不相干的对象
4,class C:  /x = Record() 只是在类中实例化一个对象,而不是,x这个实例化对象作为C这个类的属性
而很明显,下面e.x这个是e的属性,这个属性是一个对象,而要查看一个对象的属性,需要e.x.val
另外,类的初始化在类被调用一开始进行,但是不是最开始,最开始被调用另有它人(忘了,你后面会学到)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-25 21:03:14 | 显示全部楼层
HZX0229 发表于 2021-2-25 20:24
1,x = Record(), 是类的实例化,x是Record类的实例化对象,如果要使用类的方法,使用类的继承即可
2,fil ...

谢谢,您的回答。还是有些问题:
第2个问题我的意思是这个语句实际上在整个代码中没用啊?
第3个问题如果c=C()\c.x=8\d=C()之后,如果c,d是两个不相关的实例对象,那为什么d.x也是8呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-2-25 21:37:53 | 显示全部楼层
Tshirt 发表于 2021-2-25 21:03
谢谢,您的回答。还是有些问题:
第2个问题我的意思是这个语句实际上在整个代码中没用啊?
第3个问题如 ...

2, 没用到要么这上面的代码错了,检查一下代码, 要么这个习题上这句代码就是多余的
3,d.x = 8, 那么C这个类里面x这个属性就是8
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-27 08:15:11 | 显示全部楼层
HZX0229 发表于 2021-2-25 21:37
2, 没用到要么这上面的代码错了,检查一下代码, 要么这个习题上这句代码就是多余的
3,d.x = 8, 那么 ...

谢谢您的回答,对于第三个问题我还是有点困惑。我的理解是有个类C,,c,d都是类C的实例对象,他们都有一个属性x,而该属性是类Record的实例对象。设置c的属性x,为什么会影响到d的属性x呢?谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-2-27 09:07:28 | 显示全部楼层
本帖最后由 HZX0229 于 2021-2-27 09:12 编辑
Tshirt 发表于 2021-2-27 08:15
谢谢您的回答,对于第三个问题我还是有点困惑。我的理解是有个类C,,c,d都是类C的实例对象,他们都有一个 ...


类好比一个人群, 属性就是这个人群的一个特征,实例化一个人群就好比是从这个人群中选出一个人,这个人就是一个实例化对象,设置一个人的属性不会影响到人群,而设置一个人群中的属性,会影响这个人群中的所有人,设置c.x 并不会影响到 d.x,  除非设置C.x。
class C:/ def __init__(self):/ self.x = 0/ c = C()/ c.x = 8/ d = C()/ print(d.x)
上面这行代码方便你理解
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-27 10:55:26 | 显示全部楼层
HZX0229 发表于 2021-2-27 09:07
类好比一个人群, 属性就是这个人群的一个特征,实例化一个人群就好比是从这个人群中选出一个人,这个 ...

感谢您的回复。您举得例子我能够理解。我的问题是在代码
import time

class Record:
    def __init__(self, initval=None, name=None):
        self.val = initval
        self.name = name
        self.filename = "record.txt"

    def __get__(self, instance, owner):
        with open(self.filename, 'a', encoding='utf-8') as f:
            f.write("%s 变量于北京时间 %s 被读取,%s = %s\n" % \
                    (self.name, time.ctime(), self.name, str(self.val)))
        return self.val

    def __set__(self, instance, value):
        filename = "%s_record.txt" % self.name
        with open(self.filename, 'a', encoding='utf-8') as f:
            f.write("%s 变量于北京时间 %s 被修改, %s = %s\n" % \
                    (self.name, time.ctime(), self.name, str(value)))
        self.val = value

class C:
    x=Record()
c=C()
c.x=8
d=C()
后,为什么d.x也是8呢?我的理解是c,d是C的实例化对象,每个对象都有一个x属性,该属性又是一个Record类的实例化对象,但为什么c.x和d.x这两个实例化对象会一样呢?谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-2-27 11:13:09 | 显示全部楼层
Tshirt 发表于 2021-2-27 10:55
感谢您的回复。您举得例子我能够理解。我的问题是在代码
import time

我第一次回复就说了,x是一个实例化对象,这里x不作为实例化对象c的一个特有属性,而是作为一个共有属性,相当于类C里面的常量,既然是共有的,那就可以通过c.x修改,可以影响到类C里面的x,self就是起到一个限制的作用,self.~这个属性是这个对象特有的,
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-27 12:00:24 | 显示全部楼层
HZX0229 发表于 2021-2-27 11:13
我第一次回复就说了,x是一个实例化对象,这里x不作为实例化对象c的一个特有属性,而是作为一个共有属性 ...

对不起耽误您时间了,“x是一个实例化对象,这里x不作为实例化对象c的一个特有属性,而是作为一个共有属性”这个我没问题,就像你前面举得例子class C:/ def __init__(self):/ self.x = 0/ c = C()/ c.x = 8/ d = C()/ print(d.x),类C的每个实例化对象都有x这个属性,例如c,d都有这个属性,但您后面说的“相当于类C里面的常量”我就不能理解了,就像您这个例子class C:/ def __init__(self):/ self.x = 0/ c = C()/ c.x = 8/ d = C()/ print(d.x)中,c.x和d.x可以不一样啊?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-2-27 13:41:01 | 显示全部楼层
Tshirt 发表于 2021-2-27 12:00
对不起耽误您时间了,“x是一个实例化对象,这里x不作为实例化对象c的一个特有属性,而是作为一个共有属 ...

关键在Record 这个类, 它有两个魔法方法, c.x = 8 它调用了__set__方法,把self.val 设置为8, d.x 这里又调用了__get__方法, 返回了self.val, 差点把我自己绕进去
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-27 15:31:30 | 显示全部楼层
HZX0229 发表于 2021-2-27 13:41
关键在Record 这个类, 它有两个魔法方法, c.x = 8 它调用了__set__方法,把self.val 设置为8, d.x 这 ...

谢谢,那么c.x=8中调用了__set__方法,把self.val 设置为8, d.x 这里又调用了__get__方法, 返回了self.val, 这两个self是一样的?我原来觉得是c.x=8中__set__是把c.x这个Record对象中的val属性设置为8,d.x是通过__get__方法获得d.x这个Record对象中的va属性,但是d没有设置过,应该就是初始化值。这样理解为什么不对呢?
谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-2-27 19:06:21 | 显示全部楼层    本楼为最佳答案   
Tshirt 发表于 2021-2-27 15:31
谢谢,那么c.x=8中调用了__set__方法,把self.val 设置为8, d.x 这里又调用了__get__方法, 返回了self. ...

c.x and d.x 是同一个对象,即x , 它们返回的都是x.val
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-2-28 11:36:49 | 显示全部楼层
HZX0229 发表于 2021-2-27 19:06
c.x and d.x 是同一个对象,即x , 它们返回的都是x.val

好的,谢谢您
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-8-19 14:00:56 | 显示全部楼层
class Attr:
    def __init__(self, key, type_):
        self.key = key
        self.type_ = type_

    def __set__(self, instance, value):
        print('in __set__')
        if not isinstance(value, self.type_):
            raise TypeError('must be %s' % self.type_)
        instance.__dict__[self.key] = value

    def __get__(self, instance, cls):
        print('in __get__', instance, cls)
        return instance.__dict__[self.key]

    def __delete__(self, instance):
        print('in __del__', instance)
        del instance.__dict__[self.key]

class Person:
    name = Attr('name', str)
    age = Attr('age', int)

p = Person()
p.name = 'tom'
#p.age = 20
p.age = '20'

找个一个比较好的解决方式,在set方法中用instance.__dict__[self.key]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-13 15:37

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表