美文网首页python
小白学Python之第十一天

小白学Python之第十一天

作者: 7季 | 来源:发表于2018-07-29 22:13 被阅读14次

    类(class)和实例(instance)

    举例:以student类为例

    1.在Python中,定义类是通过class关键字来定义的,class后面紧跟的是类名,即Student类,类名通常是大写字母开头,后面是(object),表明该类是从哪个类继承下来的。如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。

    2.定义好了Student类,就可以根据Student类来创建出Student的实例,创建实例是通过类名+()实现的:

    说明:变量bart指向的就是一个Student的实例,后面的

    是内存地址,每个object的地址都是不一样的,而Student本身则是一个类

    可以自由的给一个实例变量绑定属性,比如,给实例bart绑定一个name属性:

    由于类可以起到模板的作用,所以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去,通过定义一个特殊的__init__方法,在创建实例的时候,就把name,score等属性绑上去:

    说明:__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__int__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。

    有了__init__方法,在创建实例的时候,就不能传入空的参数,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去,

    和普通函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,在调用时,不用传递该参数,除此之外,类的方法与普通函数没有射门区别,所以仍然可以使用默认参数,可变参数,关键字参数和命名关键字参数。

    数据封装及访问限制

    生活化的封装:我们在使用电视机时,不用知道电视机里的具体细节,只需要再用的时候,按下遥控器就可以了,这是功能的封装。

    在使用支付宝时,不用知道支付宝的接口以及后台出路数据的能力,只需要扫码就可以了,这是方法的封装。

    封装的意义:

    封装不是单纯意义上的隐藏

    封装数据的主要原因是保护隐私

    封装方法的主要原因是隔离复杂度

    在编程里,对外提供接口,表示这个接口的函数,通常称为接口函数。

    封装分为两个层面:

    第一层面:创建类和对象时,分别创建两者的名称空间,只能通过类名加“.”或obj.的方式访问里面的名字

    第二层面:类中把某些属性和方法隐藏起来,或定义为私有,只在类的内部使用,在类的外部无法访问,或者留下少量的接口(函数)访问。

    在python中,使用双下划线的方式实现隐藏属性(设置为私有属性)

    举例

    用定义的创建一个老师t1和一个学生s1

    分别调用老师和学生的姓名和年龄等特征:

    返回以下信息

    调用老师的教书技能和学生的学习技能

    返回信息如下

    把这两类的一些属性隐藏下,

    在次创建老师和学生实例

    调用老师和学生特征:

    然后返回时出错了

    在调用老师和学生的技能

    返回如上,还是能正常返回的。

    如何用外部代码获取隐藏信息

    可以给Student类增加get_name和get_age或get_course

    外部修改代码再给Student类增加set_age方法,可以对参数检查,避免传入无效的参数。

    注意:

    1.在Python中变量名类似__xxx__的,也就是使用这种方法以双下划线开头,并且以双下划綫结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以不能用__name__、__age__这样的变量。

    2.以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以直接访问的,但是我们会默认为是私有变量,不随便访问。

    3.双划线开头的实例变量可以通过以下方式访问。但不建议这么干,因为不同版本python解释器可能会把__age改成不同的变量名

    先看看t1,s1的名称空间

    从返回来看,名称空间名字变了。那我们来访问名称空间的key 

    从返回来看,我们可以通过‘_类名__属性’的方式来访问其内部属性值

    和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然他们都是同一类的不同实例,但拥有的变量名称都可能不同。

    继承和多态

    继承

    在OOP程序设计时,当我们定义一个class的时候,可以从现有的class继承,新的class称为子类,而被继承的class称为基类、父类或超类(Base class、Super class)

    举例:我们已经编写了一个名为Father的class,有一个walk()方法可以直接打印:

    当我们需要编写Bigson和Twoson类时,就可以直接从Father类继承:

    对于Bigson来说,Father就是父类,对于Father来说,Bigson是它的子类。

    继承的优点就是子类可以获得父类的全部功能,

    由于Father实现了walk()方法,因此Bigson和Twoson作为它的父类也获得了这种方法

    运行结果如下:

    第二个好处就是修改下代码就可以实现有自己特点的walk()方法。

    再次运行

    运行结果就有自己的特点了。

    多态

    当子类和父类都存在walk()的方法时,子类的walk()会覆盖父类的walk(),在代码运行的时候,总是会调用子类的walk()。

    这样,就得出了继承的另一个好处:多态

    我们在定义class的时候,其实可以理解为我们定义了一个数据类型。

    判断一个变量是否是某个类型可以用isinstance()判断:

    但是可以试试

    返回结果来看,c不只是Bigson还是Father。

    可以理解,因为Bigson是从Father继承下来的,所以是Bigson必定也是Father,但反过来就不行了。

    多态的第二个优点就是

    一个接受父类赋值的函数,可以接受子类的赋值,并且不用做修改就可直接执行。

    对于我们赋值的变量,我们只知道它是父类类型,无需确切知道它的子类型,都可以调用相同的方法,而具体调用的某种方法作用在父类或哪个子类上,由运行的该对象的确切类型决定,这就是多态的威力:调用方只管调用,不管细节,当新增一种子类时,只要确保方法编写正确,不用管原来的代码是如何调用的,这就是著名的“开闭”原则:

    对扩展开放:允许新增子类

    对修改封闭:不需要父类就可执行的函数

    继承可以一级一级传下去,任何类都可追溯到根类object。

    静态语言 vs 动态语言

    对于静态语言(e.g JAVA)来说,如果传入Father类型,则传入的对象必须是Father类型或它的子类,否则,将无法调用walk()方法

    对于Python这样的动态语言来说,则不一定需要传入Father类型,我们只需要传入的对象有一个walk()方法就可以了。

    这就是动态语言的“鸭子类型”,它并不需要严格的继承体系,一个对象只要看起来“看起来像鸭子,走起路来像鸭子”,那它就可以被看做鸭子。

    Python的“file-like object”就是一种鸭子类型,对真正的文件对象,它有一个read()方法,返回内容,但是,许多对象,只要有read()方法都被看做是“file-like object”,你不一定要传入真正的文件对象,完全可以传入任何实现了read()方法的对象。

    相关文章

      网友评论

        本文标题:小白学Python之第十一天

        本文链接:https://www.haomeiwen.com/subject/uvitvftx.html