鱼C论坛

 找回密码
 立即注册
查看: 1884|回复: 1

[已解决]类变量会共享变量吗

[复制链接]
发表于 2022-10-10 22:55:04 | 显示全部楼层 |阅读模式

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

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

x
类变量会共享变量吗?小甲鱼在讲类的时候说不会,视频地址:
  1. 发不了URL,视频是 【Python教程】《零基础入门学习Python》最新版(2022年09月29日更新)P59    6:02的地方
复制代码

但是在这个类A中,我用self.aList.extend(value)每个对象都好像共享了这个类变量aList
而当我用self.aList = value时就不会有这种情况了,这是怎么回事,各位大佬能解释一下吗


  1. class A:
  2.     aList = []

  3.     def __init__(self, value=None):
  4.         if value is None:
  5.             return
  6.         self.aList.extend(value)  # 这是用self.aList.extend(value)
  7.         print(self.aList)


  8. aas = [A() for _ in range(10)]

  9. d = A(aas)
  10. print(d.aList)
  11. print(d.aList[0].aList)

  12. # 结果如下
  13. [<__main__.A object at 0x000001A0DB5C5D20>, <__main__.A object at 0x000001A0DB5C5FC0>, <__main__.A object at 0x000001A0DB5C5FF0>, <__main__.A object at 0x000001A0DB5C5750>, <__main__.A object at 0x000001A0DB5C5E70>, <__main__.A object at 0x000001A0DB5C61A0>, <__main__.A object at 0x000001A0DB5C61D0>, <__main__.A object at 0x000001A0DB5C6200>, <__main__.A object at 0x000001A0DB5C6230>, <__main__.A object at 0x000001A0DB5C6170>]
  14. [<__main__.A object at 0x000001A0DB5C5D20>, <__main__.A object at 0x000001A0DB5C5FC0>, <__main__.A object at 0x000001A0DB5C5FF0>, <__main__.A object at 0x000001A0DB5C5750>, <__main__.A object at 0x000001A0DB5C5E70>, <__main__.A object at 0x000001A0DB5C61A0>, <__main__.A object at 0x000001A0DB5C61D0>, <__main__.A object at 0x000001A0DB5C6200>, <__main__.A object at 0x000001A0DB5C6230>, <__main__.A object at 0x000001A0DB5C6170>]
  15. [<__main__.A object at 0x000001A0DB5C5D20>, <__main__.A object at 0x000001A0DB5C5FC0>, <__main__.A object at 0x000001A0DB5C5FF0>, <__main__.A object at 0x000001A0DB5C5750>, <__main__.A object at 0x000001A0DB5C5E70>, <__main__.A object at 0x000001A0DB5C61A0>, <__main__.A object at 0x000001A0DB5C61D0>, <__main__.A object at 0x000001A0DB5C6200>, <__main__.A object at 0x000001A0DB5C6230>, <__main__.A object at 0x000001A0DB5C6170>]
复制代码


  1. class A:
  2.     aList = []

  3.     def __init__(self, value=None):
  4.         if value is None:
  5.             return
  6.         self.aList = value #这是用self.aList = value
  7.         print(self.aList)


  8. aas = [A() for _ in range(10)]

  9. d = A(aas)
  10. print(d.aList)
  11. print(d.aList[0].aList)


  12. #结果如下
  13. [<__main__.A object at 0x000001E6C0385D20>, <__main__.A object at 0x000001E6C0385FC0>, <__main__.A object at 0x000001E6C0385FF0>, <__main__.A object at 0x000001E6C0385750>, <__main__.A object at 0x000001E6C0385E70>, <__main__.A object at 0x000001E6C03861A0>, <__main__.A object at 0x000001E6C03861D0>, <__main__.A object at 0x000001E6C0386200>, <__main__.A object at 0x000001E6C0386230>, <__main__.A object at 0x000001E6C0386170>]
  14. [<__main__.A object at 0x000001E6C0385D20>, <__main__.A object at 0x000001E6C0385FC0>, <__main__.A object at 0x000001E6C0385FF0>, <__main__.A object at 0x000001E6C0385750>, <__main__.A object at 0x000001E6C0385E70>, <__main__.A object at 0x000001E6C03861A0>, <__main__.A object at 0x000001E6C03861D0>, <__main__.A object at 0x000001E6C0386200>, <__main__.A object at 0x000001E6C0386230>, <__main__.A object at 0x000001E6C0386170>]
  15. []
复制代码
最佳答案
2022-10-11 10:01:50

类变量属于这一类,所有此类的实例都会共享这个变量,即类变量

而类变量的赋值方式是在类中且类的方法外的空间,进行 变量名 = 属性值 这样赋值,被称为类变量

而在类方法中,进行 变量名 = 属性值 这样的赋值属于局部变量,出了这个方法就无法找到此变量了

最后 self.变量名 = 属性值 这种赋值方式的变量名被称为 实例变量,即每个实例对象都会有的属性,但不共享

而这里共享是因为,aList 这个变量在 A 类中是类变量,当你第一次创造实例在初始化方法中又进行了 self.aList 列表的合并

此时 self.aList 列表,会先在实例对象中寻找 aList 属性,发现实例对象没有 aList 属性,就会去类变量中找 aList,所以此时找到了 aList 这个类属性

你对这个类属性进行列表合并,不是创建新的列表,而是在原列表上进行合并

自然会共享所有整个类对象中的 aList 变,但第二段代码,你是对这个实例对象进行重新赋值,那么此时就是进行实例属性的赋值,即 self.aList 就会 "覆盖" 类变量的 aList

当你再进行访问时,你访问的是实例的 aList ,而不是类本身定义的类变量 aList,看下下面这两段代码,可能更有助于你理解:

  1. class A:
  2.     aList = []

  3.     def __init__(self, value=None):
  4.         if value is None:
  5.             return
  6.         self.aList.extend(value)  # 这是用self.aList.extend(value)
  7.         print(id(self.aList))


  8. print(id(A.aList))
  9. aas = [A() for _ in range(10)]

  10. d = A(aas)
  11. print(id(d.aList))
  12. print(id(d.aList[0].aList))

  13. # 输出结果一定会是四个相同的地址,因为都是类变量 aList
复制代码


  1. class A:
  2.     aList = []

  3.     def __init__(self, value=None):
  4.         if value is None:
  5.             return
  6.         self.aList = value
  7.         print(id(self.aList)) # # 第二个 print


  8. print(id(A.aList))  # 第一个 print
  9. aas = [A() for _ in range(10)]

  10. d = A(aas)
  11. print(id(d.aList))  # 第三个 print
  12. print(id(d.aList[0].aList)) # 第四个 print

  13. # 输出结果,一定是第一个 print 和 第四个 print 地址值相同,其余两个相同,因为 前者是类属性,后者是实例属性
复制代码



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-10-11 10:01:50 | 显示全部楼层    本楼为最佳答案   

类变量属于这一类,所有此类的实例都会共享这个变量,即类变量

而类变量的赋值方式是在类中且类的方法外的空间,进行 变量名 = 属性值 这样赋值,被称为类变量

而在类方法中,进行 变量名 = 属性值 这样的赋值属于局部变量,出了这个方法就无法找到此变量了

最后 self.变量名 = 属性值 这种赋值方式的变量名被称为 实例变量,即每个实例对象都会有的属性,但不共享

而这里共享是因为,aList 这个变量在 A 类中是类变量,当你第一次创造实例在初始化方法中又进行了 self.aList 列表的合并

此时 self.aList 列表,会先在实例对象中寻找 aList 属性,发现实例对象没有 aList 属性,就会去类变量中找 aList,所以此时找到了 aList 这个类属性

你对这个类属性进行列表合并,不是创建新的列表,而是在原列表上进行合并

自然会共享所有整个类对象中的 aList 变,但第二段代码,你是对这个实例对象进行重新赋值,那么此时就是进行实例属性的赋值,即 self.aList 就会 "覆盖" 类变量的 aList

当你再进行访问时,你访问的是实例的 aList ,而不是类本身定义的类变量 aList,看下下面这两段代码,可能更有助于你理解:

  1. class A:
  2.     aList = []

  3.     def __init__(self, value=None):
  4.         if value is None:
  5.             return
  6.         self.aList.extend(value)  # 这是用self.aList.extend(value)
  7.         print(id(self.aList))


  8. print(id(A.aList))
  9. aas = [A() for _ in range(10)]

  10. d = A(aas)
  11. print(id(d.aList))
  12. print(id(d.aList[0].aList))

  13. # 输出结果一定会是四个相同的地址,因为都是类变量 aList
复制代码


  1. class A:
  2.     aList = []

  3.     def __init__(self, value=None):
  4.         if value is None:
  5.             return
  6.         self.aList = value
  7.         print(id(self.aList)) # # 第二个 print


  8. print(id(A.aList))  # 第一个 print
  9. aas = [A() for _ in range(10)]

  10. d = A(aas)
  11. print(id(d.aList))  # 第三个 print
  12. print(id(d.aList[0].aList)) # 第四个 print

  13. # 输出结果,一定是第一个 print 和 第四个 print 地址值相同,其余两个相同,因为 前者是类属性,后者是实例属性
复制代码



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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-20 08:12

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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