Tshirt 发表于 2021-2-25 16:59:04

第046讲:魔法方法:描述符(Property的原理)中的疑问

在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.谢谢
       

HZX0229 发表于 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
另外,类的初始化在类被调用一开始进行,但是不是最开始,最开始被调用另有它人(忘了,你后面会学到)

Tshirt 发表于 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呢?

HZX0229 发表于 2021-2-25 21:37:53

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

2, 没用到要么这上面的代码错了,检查一下代码, 要么这个习题上这句代码就是多余的
3,d.x = 8, 那么C这个类里面x这个属性就是8

Tshirt 发表于 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呢?谢谢

HZX0229 发表于 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)
上面这行代码方便你理解

Tshirt 发表于 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这两个实例化对象会一样呢?谢谢

HZX0229 发表于 2021-2-27 11:13:09

Tshirt 发表于 2021-2-27 10:55
感谢您的回复。您举得例子我能够理解。我的问题是在代码
import time



我第一次回复就说了,x是一个实例化对象,这里x不作为实例化对象c的一个特有属性,而是作为一个共有属性,相当于类C里面的常量,既然是共有的,那就可以通过c.x修改,可以影响到类C里面的x,self就是起到一个限制的作用,self.~这个属性是这个对象特有的,

Tshirt 发表于 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可以不一样啊?

HZX0229 发表于 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, 差点把我自己绕进去{:5_104:}

Tshirt 发表于 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没有设置过,应该就是初始化值。这样理解为什么不对呢?
谢谢

HZX0229 发表于 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

Tshirt 发表于 2021-2-28 11:36:49

HZX0229 发表于 2021-2-27 19:06
c.x and d.x 是同一个对象,即x , 它们返回的都是x.val

好的,谢谢您

zdxhf 发表于 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__ = value

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

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

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

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

找个一个比较好的解决方式,在set方法中用instance.__dict__
页: [1]
查看完整版本: 第046讲:魔法方法:描述符(Property的原理)中的疑问