前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据和自省《私有属性、__dict__》

数据和自省《私有属性、__dict__》

作者头像
清菡
发布2022-04-27 19:26:48
3100
发布2022-04-27 19:26:48
举报
文章被收录于专栏:清菡软件测试清菡软件测试

目录

  • 一、私有属性
    • 1.通过代码查看单下划线和双下划线的定义有啥区别
    • 2.查看某个类所有的属性
    • 3.访问双下划线开头的私有属性
    • 4.修改之前写的单例模式
    • 5.总结单下划线和双下划线定义的区别
  • 二、私有属性能不能继承
    • 公有属性和私有属性都能继承
  • 三、__dict__
    • 1.查看已经继承Test类的A类的属性
    • 2.查看父类的属性
    • 3.在已经继承Test类的A类里面定义属性
    • 4.如果A类不继承Test类
    • 5.总结

一、私有属性

  • 类里面定义的变量叫类属性,那么类属性有两种。分为:公有属性和私有属性。
  • 私有属性定义:
    • 单下划线开头:_attr
    • 双下划线开头:__attr

Python里面的私有属性也是个伪私有属性,没有真正的私有化。

私有属性在官方文档里是这样说的:定义一个公用的接口。公用的接口里面的类属性是一个下划线或者两个下划线开头的,那么这些属性被视为私有属性。

私有属性就是说:这个接口是公有的,如果你要用我这个类里面的私有属性,可以用。但是如果我把私有属性修改了,我就不会通知你。

就是说,给你建议:只要用下划线标识了,我这个属性只在类里面用,你不要在外面用,你在外面用了也可以。但是开发者在类里面改了私有属性,他不会告诉你。你的代码在外面调用了这个属性,他在这个类里面把属性改掉了,你的代码就直接报错了。

1.通过代码查看单下划线和双下划线的定义有啥区别

类属性可以通过类和实例对象去访问。单下划线开头的私有属性是可以访问的。

双下划线开头的私有属性,对外不能直接访问。 提示没有__attr3这个属性,因为它被改了个名字。

代码语言:javascript
复制
class Test:
   attr1=1000 #公有属性
   #私有属性
   _attr2=3000
   __attr3=4000
c = Test()

#类属性可以通过类和实例对象去访问。

#这个是公有属性。
# print(Test.attr1)#通过类去访问。
# print(c.attr1)#通过实例对象去访问。

#单下划线开头的私有属性。
# print(Test._attr2)
# print(c._attr2)

#双下划线开头的私有属性。
# 双下划线开头的私有属性,对外不能直接访问。
print(Test.__attr3)

运行结果

双下划线开头的私有属性,对外不能直接访问,为了保护这个变量。(对外改了一个名字)

2.查看某个类所有的属性

类也是一个对象。创建一个对象的时候,Python会自动给对象添加一个__dict__的属性。这个里面包含了这个对象所有的属性值。

所有的属性会以键值对存在里面。那么看看Test这个类里面的属性:

代码语言:javascript
复制
class Test:
   attr1=1000 #公有属性
   #私有属性
   _attr2=3000
   __attr3=4000
c = Test()

#类属性可以通过类和实例对象去访问。

#这个是公有属性。
# print(Test.attr1)#通过类去访问。
# print(c.attr1)#通过实例对象去访问。

#单下划线开头的私有属性。
# print(Test._attr2)
# print(c._attr2)

#双下划线开头的私有属性。
# 双下划线开头的私有属性,对外不能直接访问,为了保护这个变量。(对外改了一个名字)
# print(Test.__attr3)

print(Test.__dict__)

运行结果

在原有的属性名前面加了一个_类名

3.访问双下划线开头的私有属性

把代码改成:print(Test._Test__attr3)

代码语言:javascript
复制
class Test:
    attr1=1000 #公有属性
    #私有属性
    _attr2=3000
    __attr3=4000
c = Test()

#类属性可以通过类和实例对象去访问。

#这个是公有属性。
# print(Test.attr1)#通过类去访问。
# print(c.attr1)#通过实例对象去访问。

#单下划线开头的私有属性。
# print(Test._attr2)
# print(c._attr2)

#双下划线开头的私有属性。
# 双下划线开头的私有属性,对外不能直接访问,为了保护这个变量。(对外改了一个名字)
# 在原有的属性名前面加了一个_类名
print(Test._Test__attr3)

# print(Test.__dict__)

运行结果

4.修改之前写的单例模式

之前写的单例模式:用的是个公有属性instance=None。当时重写个new方法实现了单例模式。

我现在在创建对象之后,在外面改了属性值。通过MyTest.instance=None把它的值改成None,在下面又可以创建新的对象了。现在判断条件又不会成立,它又会创建对象了。

代码语言:javascript
复制
class MyTest(object):
    instance=None

    def __new__(cls, *args, **kwargs):
        if not cls.instance:
            cls.instance=object.__new__(cls)
            return cls.instance
        else:
            return cls.instance

t1=MyTest()
t1.name="QingHan"
MyTest.instance=None

为了单例模式更安全一点,在这里选择用私有属性。 代码改成这样:

代码语言:javascript
复制
class MyTest(object):
    __instance=None

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance=object.__new__(cls)
            return cls.__instance
        else:
            return cls.__instance

t1=MyTest()
t1.name="QingHan"

以后定义单例模式的时候,记住这个地方用私有属性:

定义私有属性后,就不能直接改了。虽然它也是可以改的,既然声明了是私有属性,别人就不会去改。

5.总结单下划线和双下划线定义的区别

通过类和实例对象都能访问私有属性。 单下划线开头的,对外是公开的,在外面可以直接访问。

双下划线开头的,为了保护这个对象,对外访问的话,改了个名字。

对外面改了个名字:在原有的属性名前面加了一个_类名

二、私有属性能不能继承?

继承可以继承父类的属性和方法。

公有属性和私有属性都能继承。

通过代码看下:

代码语言:javascript
复制
class Test:
    attr1=1000 #公有属性
    #私有属性
    _attr2=3000
    __attr3=4000



# c = Test()

#类属性可以通过类和实例对象去访问。

#这个是公有属性。
# print(Test.attr1)#通过类去访问。
# print(c.attr1)#通过实例对象去访问。

#单下划线开头的私有属性。
# print(Test._attr2)
# print(c._attr2)

#双下划线开头的私有属性。
# 双下划线开头的私有属性,对外不能直接访问,为了保护这个变量。(对外改了一个名字)
# 在原有的属性名前面加了一个_类名。
# print(Test._Test__attr3)
# print(c._Test__attr3)
# print(Test.__dict__)

#私有属性的继承问题
class A(Test):
    pass

a=A()
print(a.attr1)
print(a._attr2)
print(a._Test__attr3)
#可以继承

运行结果

三、__dict__

__dict__是个魔法属性。这个属性就是我们创建一个对象的时候,它会自动给这个对象添加一个__dict__属性。

因为__dict__属性的存在,如果我们定义一个类,因为__dict__的存在,它会造成内存的消耗。

1.查看已经继承Test类的A类的属性

通过__dict__来看类所用的属性。这个A类里面没有定义任何一个类属性,自动添加了2个属性在里面, 父类的属性没有过来:

代码语言:javascript
复制
class Test:
    attr1=1000 #公有属性
    #私有属性
    _attr2=3000
    __attr3=4000



# c = Test()

#类属性可以通过类和实例对象去访问。

#这个是公有属性。
# print(Test.attr1)#通过类去访问。
# print(c.attr1)#通过实例对象去访问。

#单下划线开头的私有属性。
# print(Test._attr2)
# print(c._attr2)

#双下划线开头的私有属性。
# 双下划线开头的私有属性,对外不能直接访问,为了保护这个变量。(对外改了一个名字)
# 在原有的属性名前面加了一个_类名。
# print(Test._Test__attr3)
# print(c._Test__attr3)
# print(Test.__dict__)

#私有属性的继承问题
class A(Test):
     pass

a=A()
#可以继承。
print(a.attr1)
print(a._attr2)
print(a._Test__attr3)

print(A.__dict__)

运行结果

2.查看父类的属性

加上这句代码print(Test.__dict__)

这个是父类的属性:

父类定义了属性,多了好多东西。

3.在已经继承Test类的A类里面定义属性

在A类里面定义属性:

代码语言:javascript
复制
class Test:
    attr1=1000 #公有属性
    #私有属性
    _attr2=3000
    __attr3=4000



# c = Test()

#类属性可以通过类和实例对象去访问。

#这个是公有属性。
# print(Test.attr1)#通过类去访问。
# print(c.attr1)#通过实例对象去访问。

#单下划线开头的私有属性。
# print(Test._attr2)
# print(c._attr2)

#双下划线开头的私有属性。
# 双下划线开头的私有属性,对外不能直接访问,为了保护这个变量。(对外改了一个名字)
# 在原有的属性名前面加了一个_类名。
# print(Test._Test__attr3)
# print(c._Test__attr3)
# print(Test.__dict__)

#私有属性的继承问题
class A(Test):
    name="QingHan"
    __name="mmmm"

a=A()
#可以继承。
print(a.attr1)
print(a._attr2)
print(a._Test__attr3)

print(Test.__dict__)
print(A.__dict__)


运行结果

子类继承父类的时候没有__dict____weakref__这2个东西。

4.如果A类不继承Test类

代码语言:javascript
复制
class Test:
    attr1=1000 #公有属性
    #私有属性
    _attr2=3000
    __attr3=4000



# c = Test()

#类属性可以通过类和实例对象去访问。

#这个是公有属性。
# print(Test.attr1)#通过类去访问。
# print(c.attr1)#通过实例对象去访问。

#单下划线开头的私有属性。
# print(Test._attr2)
# print(c._attr2)

#双下划线开头的私有属性。
# 双下划线开头的私有属性,对外不能直接访问,为了保护这个变量。(对外改了一个名字)
# 在原有的属性名前面加了一个_类名。
# print(Test._Test__attr3)
# print(c._Test__attr3)
# print(Test.__dict__)

#私有属性的继承问题
class A:
    name="QingHan"
    __name="mmmm"

a=A()
#可以继承。
# print(a.attr1)
# print(a._attr2)
# print(a._Test__attr3)
print(Test.__dict__)
print(A.__dict__)

不是继承的话,会多出这2个东西:

运行结果

多出这2个东西,会消耗内存。

5.总结

如果通过继承的方式定义类,父类已经有__dict____weakref__属性了,所以子类不会再有这两个属性了,可以节省内存。

如果定义一个类只创建一个对象,这个对象会给你绑定一个__dict__属性。那么__dict__里面存了一些数据。

如果这个类创建了特别多的对象,每个对象都会有一个__dict__属性。

这个时候,__dict__属性会占用特别多的内存空间。

代码语言:javascript
复制

class A():
    def a(self):
        print("洗衣服")
    def b(self):
        print("吃饭")

haier=A()
haier.a()

qinghan=A()
qinghan.b()


print(A.__dict__)

运行结果

除标明“图片来自网络”的图片,其它文章中的图片皆为本人所画,计算机知识都一样,如有雷同,纯属巧合。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 清菡软件测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
    • 一、私有属性
      • 1.通过代码查看单下划线和双下划线的定义有啥区别
    • 2.查看某个类所有的属性
      • 3.访问双下划线开头的私有属性
      • 4.修改之前写的单例模式
      • 5.总结单下划线和双下划线定义的区别
    • 二、私有属性能不能继承?
      • 公有属性和私有属性都能继承。
    • 三、__dict__
      • 1.查看已经继承Test类的A类的属性
      • 2.查看父类的属性
      • 3.在已经继承Test类的A类里面定义属性
      • 4.如果A类不继承Test类
      • 5.总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档