python---核心知识4之面向对象属性补充

属性分为公有属性,受保护属性以及私有属性,在python里面并不是用修饰符来限制属性,而是通过命名规则来限制,下面我们就来看看各种属性的命名规则以及可使用范围:

公有属性:就是我们平时最常用的变量,直接就是变量=某值,可用范围:类内部,子类内部,模块的其他区域,其他模块,我们可以看出公有属性在哪里都是可被访问的;

受保护属性:就是在变量的前面加一个下划线,可用范围:类内部,子类内部,模块的其他区域访问:受警告,其他模块:通过import方式导入模块,受警告访问,通过from import导入,由__all__指明对应变量则能访问,没有用__all__指明对应变量则不能访问,

__all__:是针对 from import * 这种导入方式,对import导入方式无效,__all__变量是一个由string元素组成的list变量。它定义了当我们使用 from import * 导入某个模块的时候能导出的符号(这里代表变量,函数,类等)。模块中使用__all__属性,则表示只导入__all__中指定的属性,因此,使用__all__可以隐藏不想被import的默认值。

私有属性:在变量的前面加两根下划线,可用范围:类内部;子类内部和模块的其他区域都不能访问,其他模块和受保护属性一致;另外还需要注意一点,只有在类内部定义的属性才是私有化属性,如果在外部定义一个实例属性,这个并不是私有化属性,换句话来说,私有化属性是针对于类的,而不是实例;

下面的代码是验证属性的可用区间:

python---核心知识4之面向对象属性补充_第1张图片

私有属性的实现机制:我们知道python里面其实并没有真正的私有化,python里面的私有化是伪私有,那么伪私有到底又是怎么实现的呢,我们可以通过__dict__来获取类的所有属性,可以看到_Person__eyes这个属性,我们可以发现原来我们命名为__eyes的属性被重命名了,被重命成了_类名属性,所以我们在其他地方通过类名来找这个属性是找不到的,既然我们知道了这个命名规则,那么我们也可以使用这个规则去找到这个属性了;

私有属性应用场景举例:私有属性主要由两个作用,第一是保护数据,不让别人直接操作数据,第二是过滤数据,过滤出正确有效的数据,比如:下面这个例子,首先年龄是每个人都有的属性,我们给人类设置了这个属性,并且给了个默认值是18,其次年龄也不是想改就改的,需要通过时间的积累,所以年龄设置成私有的,不让外界直接去修改,私有属性只有在类内部才能访问,所以我们提供了两个方法给外部,外部想要访问我们的私有属性,就要通过这两个方法,一个是修改,一个是获取,这样我们就保护了数据,然后在修改的时候,我们设置了修改成功的条件,这样我们便过滤了数据,这就是私有化属性的例子了;

python---核心知识4之面向对象属性补充_第2张图片

补充:针对一些命名为xx_和__xx__这两种写法,并不是控制属性权限的写法,第一种是用于属性名和系统关键字的区分,第二种是系统内置的属性或者方法会这样写;

经典类和新式类:

经典类:没有继承object

新式类:继承Object

在python2.x版本,写的类默认不继承object,是经典类,而python3.x版本,写的类默认继承object,是新式类,怎么区分经典类还是新式类呢,是根据类的一个属性 __bases__,如果结果是object则是新式类,反之则是经典类;

现在我们来讲讲property的使用,其实property也就是一个装饰器,把它用在函数上面,会使得函数增加其他功能,但是property在新式类和经典类的使用上面会有所不同,首先我们来看看新式类:新式类就是继承自Object的类,首先我们定义了一个私有属性__age,然后也提供了get和set方法,其实外部想访问私有属性,通过这两个方法就可以了,但是为了代码的优雅,我们就使用了property这个类,我们跟进property的源码去看,发现需要接收几个参数,也找到了他的用法,其实property装饰器的作用就是把操作属性的方法,重新包装,使得访问私有属性时更加便捷;

class Person(object):

    def __init__(self):

        self.__age=18

    def getage(self):

        return self.__age

    ef setage(self,value):

        self.__age=value

    age = property(getage,setage)

person=Person()

print(person.age)

person.age=20

print(person.age,person.__dict__)

第二种使用方法:如图所示,第二种方法则完全是装饰器模样;

python---核心知识4之面向对象属性补充_第3张图片

那么针对经典类又有什么不同呢,其实property对经典类和新式类的写法都是一样的,不同的是经典类只能使用读取这个属性,其他两个属性用不上,所以建议一般情况下都使用新式类比较好;

只读属性的第二种实现方法,通过重写__setattr__方法,因为当我们通过对象.属性=value这样新增或者修改属性的时候会在__setattr__方法里面去执行属性的操作,那么我们就可以重写这个方法,当要执行修改的时候屏蔽掉就可以了:当然通过这种方法也不是百分之百的安全,我们还可以直接通过__dict__字典去修改内存里面的值,这样就没办法了,因为我们没办法重写字典的修改方法;

class Person:

    def __init__(self):

        self.age=18

    def __setattr__(self, key, value):

        if self.__dict__.__contains__(key):

            pass

    else:

        self.__dict__[key]=value

p=Person()

print(p.age,p.__dict__)

p.age=666

print(p.age,p.__dict__)

你可能感兴趣的:(python---核心知识4之面向对象属性补充)