shatanzongcai 发表于 2020-7-29 21:49:32

self.属性在类中的作用域

本帖最后由 shatanzongcai 于 2020-7-29 21:51 编辑

各位鱼油晚上好。我遇到了一个问题:
class People(object):
    type = "human"
    def __init__(self, name, age, gender):
         self.name = name
         self.age = age
         self.gender = gender
         #info =
         print(locals())

    def __str__(self):
         print(locals())
         #print(info)
         return f"这个人的名字是:{self.name},年龄是:{self.age},性别是:{self.gender}"


p = People("marry", 16, "female")
print(p)
暂时不看我注释掉的那两行,得出来的结果是:
>>>{'self': <__main__.People object at 0x00000286D0136400>, 'name': 'marry', 'age': 16, 'gender': 'female'}
>>>{'self': <__main__.People object at 0x00000286D0136400>}
>>>这个人的名字是:marry,年龄是:16,性别是:female也就是说self.属性即使是定义在一个方法中,也可以在另外一个方法(非静态方法和类方法)中调用,这么看来和type这个类属性的作用域是一样的。但是把注释的两行拿掉之后,就会报错,报错的原因是info没有定义。在这里info的作用域就限定在了__init__里面。

可是当我使用locals()的时候,我看到name,age,gender是在__init__方法里,它们并不存在在__str__方法里,为何__str__可调用呢?

而且当我在class的最后打印locals()
    以上略
    def __str__(self):
         print(locals())
         <font color="Red">#print(info)</font>
         return f"这个人的名字是:{self.name},年龄是:{self.age},性别是:{self.gender}"
    print(locals())
返回的是:
>>>{'__module__': '__main__', '__qualname__': 'People', 'type': 'human', '__init__': <function People.__init__ at 0x0000025ED3F5D700>, '__str__': <function People.__str__ at 0x0000025ED3E7F310>}
>>>{'self': <__main__.People object at 0x00000286D0136400>, 'name': 'marry', 'age': 16, 'gender': 'female'}
>>>{'self': <__main__.People object at 0x00000286D0136400>}
>>>这个人的名字是:marry,年龄是:16,性别是:female返回中并没有并没有出现name之类的。



所以self.属性的作用域是整个类的内部吗?为什么可以这样呀?
而且明明我把print(locals())写在类的最后,为什么反而它是第一个被打印出来的呢?



永恒的蓝色梦想 发表于 2020-7-29 21:54:22

可是当我使用locals()的时候,我看到name,age,gender是在__init__方法里,它们并不存在在__str__方法里,为何__str__可调用呢?请见代码 4-6 行:         self.name = name
         self.age = age
         self.gender = gender这里不是在给对象添加了属性吗?所以后面的return f"这个人的名字是:{self.name},年龄是:{self.age},性别是:{self.gender}"不会报错。

永恒的蓝色梦想 发表于 2020-7-29 21:55:13

所以self.属性的作用域是整个类的内部吗?为什么可以这样呀?不是啊,在对象内部。

永恒的蓝色梦想 发表于 2020-7-29 21:56:13

而且明明我把print(locals())写在类的最后,为什么反而它是第一个被打印出来的呢?因为 print(locals()) 是在类的定义时运行的,其余都是运行时打印的。

shatanzongcai 发表于 2020-7-29 22:06:08

永恒的蓝色梦想 发表于 2020-7-29 21:54
请见代码 4-6 行:这里不是在给对象添加了属性吗?所以后面的不会报错。

为什么明明定义在另外一个方法中,__str__方法也可以调用得到呢,是说self.属性在对象里面有点类似于作用域最大变量吗,enclosing那样的?

shatanzongcai 发表于 2020-7-29 22:06:40

永恒的蓝色梦想 发表于 2020-7-29 21:56
因为 print(locals()) 是在类的定义时运行的,其余都是运行时打印的。

好的,这个我试着跑了一下,确实是这样的,感谢

shatanzongcai 发表于 2020-7-29 22:07:57

永恒的蓝色梦想 发表于 2020-7-29 21:55
不是啊,在对象内部。

这个是我写错了,我想说的就是在对象内部。为何它的作用域可以是整个对象内部呢

永恒的蓝色梦想 发表于 2020-7-29 22:10:54

shatanzongcai 发表于 2020-7-29 22:06
为什么明明定义在另外一个方法中,__str__方法也可以调用得到呢,是说self.属性在对象里面有点类似于作用 ...

你给这个对象添加了属性,所以说可以访问啊。

永恒的蓝色梦想 发表于 2020-7-29 22:11:29

shatanzongcai 发表于 2020-7-29 22:07
这个是我写错了,我想说的就是在对象内部。为何它的作用域可以是整个对象内部呢

你给对象赋值不是整个对象内部还能是啥呢?

Stubborn 发表于 2020-7-29 22:11:30

本帖最后由 Stubborn 于 2020-7-29 22:12 编辑

locals() 函数会以字典类型返回当前位置的全部局部变量。


为什么类的属性(数据)成员驻留在实例命名空间,而类的方法成员驻留在类命名空间?理解这一问题是非常重要的。

当一个实例被构建好,类的属性(数据)成员就在`__init__`建立起来了。原始的赋值语句`self.args=0`,其中`self`是实例的标识符。在这种赋值中,`self.args`中的`self`作为限定符使用,这使得`args`标识符直接添加到实例命名空间。

而类的方法成员都是在类中声明的,所以它也与类命名空间中的自身命名相关连

永恒的蓝色梦想 发表于 2020-7-29 22:11:53

下次这种4鱼币的悬赏不如发提问帖啦{:10_277:}

Stubborn 发表于 2020-7-29 22:13:22

永恒的蓝色梦想 发表于 2020-7-29 22:11
下次这种4鱼币的悬赏不如发提问帖啦

不要鱼币,我们都是热心的程序猿

shatanzongcai 发表于 2020-7-29 22:28:05

永恒的蓝色梦想 发表于 2020-7-29 22:11
你给对象赋值不是整个对象内部还能是啥呢?

我在上面使用了locals()来表示我的疑惑。self.name是在__init__被定义,我想问的是,它在__init__被定义之后,其他的方法为什么能够直接调用这儿self.name。而不是像普通的内嵌函数一样需要使用nonlocal之类的。是因为self.name被定义后,其实就好像是类属性的type一样吗?之所以我不能用最后的print(locals())打印出name之类的变量,是因为我没有实例化,所以打不出来吗?

shatanzongcai 发表于 2020-7-29 22:33:55

Stubborn 发表于 2020-7-29 22:11
locals() 函数会以字典类型返回当前位置的全部局部变量。




你说的实例命名空间是什么?是说实例的属性其实是放在实例的内存吗?这个我是知道的

shatanzongcai 发表于 2020-7-29 22:47:04

永恒的蓝色梦想 发表于 2020-7-29 22:11
你给对象赋值不是整个对象内部还能是啥呢?

我看了很多帖子并没有人告诉我为什么是这样的,self.属性的作用域是整个对象这一点我写了一点代码验证了,但我其实想知道为什么。如果这个不重要的话我就不问了,以后还是直接拿来用。

永恒的蓝色梦想 发表于 2020-7-29 22:50:50

shatanzongcai 发表于 2020-7-29 22:47
我看了很多帖子并没有人告诉我为什么是这样的,self.属性的作用域是整个对象这一点我写了一点代码验证了 ...

打个不太恰当的比喻:
你是一个人,你有两只手,这两只手不是你的还能是谁的?

永恒的蓝色梦想 发表于 2020-7-29 22:54:45

shatanzongcai 发表于 2020-7-29 22:28
我在上面使用了locals()来表示我的疑惑。self.name是在__init__被定义,我想问的是,它在__init__被定 ...

再次打个不太恰当的比喻。

你在储蓄罐里放了一元钱,你的妈妈把这一元钱取了出来。不都是可以得到这一元钱的么?

Stubborn 发表于 2020-7-29 23:08:37

本帖最后由 Stubborn 于 2020-7-29 23:11 编辑

shatanzongcai 发表于 2020-7-29 22:33
你说的实例命名空间是什么?是说实例的属性其实是放在实例的内存吗?这个我是知道的

对呀,实例的属性其实是放在实例的内存。现在还有什么疑问的咩?

self.属性 -> `self`是实例的标识符。

比如 boj = Class()    obj和 self 等同。

有时候你在类里面会见到sefl和cls

self 就表示实例的标识符 比如obj   cls 就表示类的标识符 比如Class

shatanzongcai 发表于 2020-7-29 23:46:02

Stubborn 发表于 2020-7-29 23:08
对呀,实例的属性其实是放在实例的内存。现在还有什么疑问的咩?

self.属性 -> `self`是实例的标识 ...

这个我知道了,locals()那个我再看看官方文档和其他帖子吧。谢谢!

shatanzongcai 发表于 2020-7-30 00:05:34

本帖最后由 shatanzongcai 于 2020-7-30 00:09 编辑

永恒的蓝色梦想 发表于 2020-7-29 22:50
打个不太恰当的比喻:
你是一个人,你有两只手,这两只手不是你的还能是谁的?

你在重复一个我已经知道的事实,我知道self该怎么用,我想知道的是self背后的机制。比方说:
class People(object):
    type = "human"

    def func1(self):
      self.data = 1

    def func2(self):
      print(self.data)

p = People()
p.func1()
p.func2()

self.data是在func1()里面定义的,为什么func2()里也可以使用。我知道它是可以这么用,但是我想知道为什么可以这么用。在普通的内嵌函数里,同样的形式不能访问得到,而在class里面有self的方法就可以做到。我问的是为什么人会长手而不是长翅膀,而不是手到底是不是长在我身上。如果你想说self就是这么用的,没有为什么,底层机制我不需要知道,那就当我没有发过这个贴,我直接把最佳给你就是了。
页: [1] 2
查看完整版本: self.属性在类中的作用域