self函数
概念
- 在使用代码创建一个新类时,通过这个类创建的每个实例对象除了共有的属性之外,每个实例对象一般会有自己的特殊的属性,如果一个一个去重新赋值,程序将会十分繁琐,且不易实现,这时就需要用到self函数的概念
- Python编写类的时候,每个函数参数第一个参数都是self,self只有在类的方法中才会有,独立的函数或方法是不必带有self的。self在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
- self指的是调用的时候类的实例
实例
- 我们创建一个类,希望这个类拥有共同属性的同时,每个实例对象有自己的名字,这时候就需要用到self函数,使用方法如下:
- 由于self函数指的是调用时的实例自身,所以在定义speak的代码中,self.name指的就是实例对象本身的name属性值
特殊方法
概念
- 在类中可以定义一些特殊方法也称为魔术方法
- 特殊方法都是形如__xxx__()这种形式
- 特殊方法不需要我们调用,它会在需要的时候自动调用
- 这里主要介绍__init__方法
实例
- __init__方法一般用来初始化类属性,它的调用方式为在创建一个实例对象时,自动调用,这样就很方便让我们可以在创建一个实例对象时对其进行属性的初始化,下面我们构造一个类,并通过__init__方法实现初始化实例对象属性name值
通过引入__init__方法,我们可以很方便给实例对象赋值,不再需要每一个去单独赋值
封装
封装的引入
- 这里引入一个例子,假如我们定义了一个车类
但是我们可以通过直接修改实例对象的属性值来对属性进行修改,这样十分不安全,例如 - 针对以上这种情况,就需要引入封装这个概念
- 出现封装的原因:
- 属性不能随意修改
- 属性不能改为任意的值
- 封装是面向对象的三大特性之一
- 封装是指隐藏对象中一些不希望被外界访问到的属性或方法
- 封装实现的方法为在需要封装的属性名前加__或_即可,借用上面的例子,我们通过封装的方法将name属性封装
- 我们可以发现属性不再能被随意修改,即使通过a.__name的方式也不能修改,但是我们可以通过a._car__name的方式进行修改
- 除了上述方法,还有一个getter()和setter()的方法来获取和设定对象的属性
- 通过定义这两个方法,就可以允许外部对属性进行获取和设定,具体操作如下
封装的补充
- 对象使用单下划线_开头的属性表示私有属性,只有类对象和子类对象自己能访问,双下划线__开头的属性表示隐藏属性只有类对象能访问
- 我们对上面的例子进行一些修改,将name设为隐藏属性__name,color设为私有属性_color,通过下面的操作体现这两者的差别
- 从上图中可以清楚的看到,隐藏属性只能通过setter函数和对象._类名__属性名的方式来更改,而私有属性依然可以通过对象._属性的方式来更改
- 封装其实只是python给属性换了一个名字,将原本的对象.属性改为了对象._类名__属性
- 通过上面的图可以看出,a.name赋值已经成功修改了a.name本身,但是由于封装将原本的a.name换了个表示形式(即换了个名字),所以在类的内部并没有修改成功
继承
概念
- 继承是面向对象的三大特性之一
- 继承让类与类之间产生关系,提升了代码的复用性,类与类之间有了关系,才有了多态的特性
- 继承的方法为在创建类的过程中,在类名后面的括号中指定父类,如果不指定父类,则默认父类为object
- 子类会继承父类的属性和方法
实例
- 创建一个动物类,在创建一个狗类作为动物类的子类
通过在类名dog后面的括号中,指定了animal作为dog的父类,从而dog继承了animal的属性和方法,从图中可以看出,a虽然是一个dog的实例,但是可以使用animal的sleep方法,这里还有一点需要注意的是,当父类和子类中都定义了相同的方法,诸如图中的run,则通过子类调用方法时,会执行子类中的方法,比如a是dog的实例,dog是animal的子类,通过a.run调用run时,就会打印狗会跑,而不是动物会跑
property装饰器
概念
- @property 是用来修饰方法的,它有两个作用:
- 创建只读属性,将方法转换为同名属性(即加入property装饰器后定义的方法在调用时就变成了属性,不需要加括号)
通过图中代码可以看出,run方法上方加上了property装饰器后,由原来的方法变成了属性,即调用run方法不需要加括号,跟调用属性相同 - 可以防止属性被修改
加上装饰器后,虽然run方法的调用方式和属性相同,但它本质上还是一个方法,所以无法通过属性的方式去修改
- 创建只读属性,将方法转换为同名属性(即加入property装饰器后定义的方法在调用时就变成了属性,不需要加括号)