能通过一个函数来约束对内部属性的调整,让它在一个合理的范围之内
python的私有属性,私有跟个体有关,
python中别人能通过访问属性,能够破坏对属性的控制,所以写了跟没写一样
在属性前面加两个__下划线,就访问不到了
如何拿到这个age
动态增加了一个属性,就是实例的属性
只不过是把你想要的age改名字,class。__age
编译器修改这个,就会在字典里增加__person__
这样就可以使用了
碰到下划线开头,你就不必要修改了,但是最好还是不修改 了
双下划线__就是私有属性,还是放在字典中的(就是改个名,知道改个名依然可以访问),只要在定义范围内,出现双下划线的属性,实例的属性,都会替你改名*
加一个下划线
注释掉
添加一个getname
使用一个_下划线开头的叫保护变量
打印一下字典
** __双下划线是私有,不是随便暴露给你的,在类的外部使用双下划线,是不允许的
在类的外面使用单下划线,_,比如_name,其实是一个保护变量(不希望进行改动和访问)**
保护变量不会改名(dict里的名字),保护变量是大家自己封的,本来是没有这个名字,
这个是python约定俗成,这是python代码的作者告诉你,不要乱动(但是其实根本挡不住,想用就用)
下划线只是一种警告,告诉你是私有保护成员,只能内部使用,不推荐你使用,你用了后果自付,、
__双下划线,私有这个属性会被改名,单下划线_是编程者约定的,不会改任何名称
其实_name和heght没什么区别,只不过下划线告诉你不要随便使用
现在看到的是属性,方法是否可以
看一下类属性
** _x=200,名字没有修改**
双下划线就改名了
但下划线就是可以直接访问的,但是i__双下划线就不行,名字都不一样了
这样写,400,500都改了
这样做就把内部的一些属性改掉,不管你是类属性还是实例
现在在_getage,__getname前面加下划线
getage,__getname都改变了
只要是在类里面定义的这个属性或者方法的名称,不管是类属性还是方法的名称,或者实例的属性,只要出现了双下划线,解释器都要给你修改名称,就造成一种你访问不到的假象,如果把字典__dict__打开了,看到了名称就想怎么访问就怎么访问
其实这个写了跟没写一样,因为使用python的人都是程序员,看两眼就知道了
通常这种方式就可以访问了
看字典就都什么都看到了
私有变量的本质:
类定义的时候,如果声明一个实例变量的时候,使用双下划线,python解释器会将其改名,转换名称为_变量名的名称,所以用原来的名字访问不到了
知道名称就可以访问了
类内的访问都受到改名的影响
类外不受改名影响,相当于重新定义一个带双下划线__,在类外面不会替它改名
保护变量加一个下划线即可,根本什么都没做,只不过告诉你不要跟普通属性直接取操作,因为这是开发者约定俗成的
** _单下划线什么都不做(编程者约定,__双下划线已经改名了,解释器会帮你做改名的工作**
改名仅限在类定义的内部实现,超出类的范围改名是没有用的
私有方法也是改个名(类属性也是同样原则)
类属性,方法,还有实例的属性都是一样的,只要使用__双下划线就全部改名
对于我们来讲,不管是私有的属性,还是私有的方法,都喜欢称为私有成员,都是member,公有的方法,和公有的属性,称为公有的成员,保护的属性和方法称为保护成员,是属性和方法,和起来叫成员
不管是什么访问控制都不能在python中阻止用户修改类的成员,python中没有绝对安全的成员
单下划线_,只是警告和提醒,请你遵守约定,不清楚不要使用
在运行时,对属性,方法,函数等进行动态替换,叫猴子补丁
其目的往往是为了通过替换,修改来增强,扩展原有代码的能力。
黑魔法,慎用
(就是原来程序有bug,打个补丁就动态修复掉
定义类person,定义方法get_score,在t1中定义
从t1中导入这个类
在t2中定义方法,这个就是未来补丁
使用猴子补丁
类似于把一个函数对象送给了一个函数
用实例来调用方法,要第一参数self
要传一个person进去
在运行之前就把补丁补上
赋值即重新定义
运行时动态去修改一个类
甚至都可以这么做
完全可以偷梁换柱,你想改什么就什么
只要认识标识符,一切都是变量,可以动态修改所有属性,类属性还是实例属性,你想修改什么就修改什么、
在运行模块中修改打补丁
属性装饰器
如果是私有成员和保护成员,类似提供getage这样的方法来进行访问,python为了提供方便,用了一个属性装饰器。,以后写面向对象,只要提供属性就是property
加了property,下面的名字最好改成未来的属性名
加一个属性装饰器,就不需要带括号进行访问了
执行一下
不能这么直接修改值,不允许设置属性
要修改还有一个设置装饰器,property称为获取装饰器,getter,
设置值要从外面塞入一个参数进来,所以要一个self和value
点击property
例子已经在这里了,setter要给一个值才能设置进去
delteter时删除的时候用的,同名age.deleter
在下面的时候使用,非常少使用
python不允许直接setter,要求必须有一个getter,有了getter,setter还是deleter随你
不用装饰器是否可以
这个就代表动态增加1个属性
这样就是定义了一个属性,这个属性叫age,设置了第一个参数,是用来getter的
,这样就只有getter没有setter,就报错了
下面写成这样,有getter才能有setter
因为property是class,本质上是个类,拿一个类作为装饰器
这个类需要几个参数,查看init初始方法,送get,set,del,参数,最后送文档字符doc
用这种方法就可以定义getter和setter,getter和setter放到函数里即可
现在不这么做,
这么一定会报错,因为只定义了getter
setter用lambda表达式写不出来,写等号会抛出异常
大多数情况都用这一种
看看这个装饰器的等价式
age.setter相当于给上面的送第二参数
尤其是功能类都会有属性装饰器的
setter和deleter必须在getter后面
其他写法就是property这种方式
lambda方式就没发写setter,赋值语句不能这么写
对象如何销毁
实例化是new,初始化是init
定义一个tom之后最后被删除了
可以直接用实例调用
等号上面是自己做的,下面是垃圾回收做的等号上面是自己做的,下面是垃圾回收做的
三个变量都指向同一个内存空间
del如果立即消亡,会看到del打印出来,等三秒之后,说明三秒之后才消亡的的
三秒之后才打印出来的
tom,tom1,tom3,代表这个对象最少被引用三次,del tom,只能说明引用计数-1
再删除一个tom1,会不会触发del,不会,程序消亡所有变量都需要消亡,tom2也要消亡
把tom2删除,触发了就有了
因为这里已经引用计数为0了,但是什么时候清楚,是垃圾回收说了算,是保不齐的时候
在程序执行完,引用计数为0,为主动调用一次垃圾回收,,没必要手动调用,在消亡的时候回再调用一次,del这个方法是消亡的时候是实例消亡的时候调用的。
前面调用多少次,都没用
这是函数不是删除对象本身的,这个是垃圾回收的事情,这里面实际上是清理工作,比如打开了很多文件描述符,最后要把这些文件描述符closs掉,但是对象的消亡不是在这里做的
比如下面的open
**类中可以定义析构函数,del
作用:销毁类的实例的时候调用,以释放占用的资源。其中就放些清理资源的代码,比如释放连接(文件描述符)。
注意这个方法不能引起对象的真正销毁,只是对象销毁的时候会自动调用它。
使用del语句删除实例,引用计数减1。当引用计数为0时,会自动调用del_ 方法。
由于Python实现了垃圾回收机制,不能确定对象何时执行垃圾回收。
**
在内存回收的时候,会在回收前自动调用这个delete方法,确保你能把占用资源释放掉,然后由垃圾回收把对象清理掉
其他的语言一般这么写
所谓重载,就是同一个方法名,但是参数数量,类型不一样,就是同一个方法的重载,参数类型不同,返回值不同,下面两套就属于重载了
python用一个就可以搞定了,天然重载
有时候可能有这样的版本,这也叫重载,参数的个数也不一样
但是在python中写成这样就不能重载了
python的传参不需要指定类型,参数注解只是一个说明而非约束性的,多个参数可以用可变参数
不需要重载就能完成别的语言中重载的功能
**学完这些理解下封装,Encapsulation
可以把一些属性隐藏起来,不能让你直接调用
能过访问控制,暴露出适当的熟悉和数据,操作提供给用户,该隐藏的隐藏起来,该保护的保护起来
**
封装的好处就是做数据的隐藏,把该隐藏的一定要隐藏,这种叫访问控制,如果真的要访问就可以用属性装饰器,getter,setter