Python官方教程阅读总结-类(Class)

类定义了一种数据类型,把数据和函数绑定在一起,创建一个新的类就创建了一个新的对象类型


方法和函数的简要区分

这里讲到类的时候,对函数和方法这两个称谓做一下区分,在类中定义的函数,我们一般称为该类的方法。两者的区别不是特别大(主要是类的对象在调用方法的时候的参数self问题),刚开始学也不用特意去区分。

1. 名称和对象

对象具有个体性, 多个名称可以绑定到同一个对象中,这在其他语言中被称为别名,在涉及到可变象的时候比较有用。

2. 作用域和命名空间

    2.1 作用域是名称到对象的映射,在python中通常是用字典类型来实现。命名空间的例子:内置的名称,模块中的全局名称,函数调用过程中的局部名称。在某种程度上,一个对象的属性也构成了一个命名空间。

    2.2 不同命名空间之间绝对没有联系,例如,不同的模块中可能都包含max函数,但是却不会引起冲突,这是因为他们属于不同的命名空间。调用的时候用 模块名.函数名()来调用,这也是前面讲的避免名称冲突的方法

    2.3 通过点(.)调用的名称称为属性,如 student.name, 其中 student 是一个对象,name是这个对象的属性。在模块中,引用名称就是属性的引用。

    2.4 属性是只读或者可写的,在可写状态下,属性可以赋值,也可以删除,如:

        student.name = "Bill"

        del student.name

    2.5 命名空间可在不同的时刻创立,并且有不同的寿命。例如:

            python内置名称所在的命名空间在解释器启动时候创立,不会被删除

            模块的全局命名空间在解释器读取模块的时候创立,在解释器退出的时候删除

            python执行的脚本或者语句属于__main__模块,有自己的命名空间

            一个函数的局部命名空间在该函数被调用的时候创立,函数返回或报错时删除(函数回归调用时的每一层有自己的一个命名空间)

    2.6 作用域是指能直接触到命名空间的区域,作用域动态得发挥作用,在程序执行过程中,至少有三种嵌套作用域,他们的命名空间是可以直接接触到的:

            最内层的作用域:包含局部名称,这是最先被查找的

            闭合函数的作用域:包含non-local, non-global

            倒数每二层的作用域:当前模块下的全局名称

            最外层作用域:内置名称(built-in names)所在的作用域,最后被查找

        通常,局部作用域引用当前函数的局部名称,在函数外,局部作用域和全局作用域都引用同一个命名空间,都是当前模块的命名空间。定义类的时候引入的是另一个局部作用域

        定义到模块内部的函数的全局作用域就是指该模块的命名空间

        如果没有 global 关键字声明,一个名称的赋值操作总是跑到最内层的作用域,赋值操作不会复制数据,只是把名称和对象(数据)绑定起来。del作用正好相反,把这种绑定解除

        所有引入新名称的操作,都使用局部作用域。例如,import 模块和函数定义就会把模块和函数绑定到local作用域中

        global声明的作用:声明该变量存在于全局作用域中,应该反应到全局作用域中

        non-local 声明的作用: 声明该变量存在于一个闭合作用域,应该反应到这个闭合作用域中

    例子:

            在上面这个例子中,do_local()作用的是最内层的局部命名空间,do_nonlocal()作用在scope_test() 所在的命名空间,do_global()作用的是模块(__main__)的命名空间。

3. 定义类

    3.1 关键字 class 来定义类,后面跟类名,然后在类中进行属性的和方法的定义,格式如下:

            类的定义多是类中方法的定义

    3.2 类的对象

        类的对象支持两种操作:对象引用和实例化操作(以上例进行说明)

        对象引用:testClass.name

        实例化:test = testClass() 

                      test.name

        上面的实例化过程其实是默认调用了类的无参构造函数来实例化,用户也可以通过__init__定义构造函数来对类进行实例化,如:

            这种情况下,实例化的时候就需要加入参数了

                    test2 = testClass2('bill', 25)

                    test2.get_Name()

                    test2.age

    3.3 实例对象

            唯一被实例对象接受的操作是属性引用,包括数据引用和方法引用,用法如上:

            test2.age是数据属性的引用

            test2.get_Name() 是方法属性的引用

    3.4 方法对象

            在上例中,test2.get_Name 就是一个方法属性的引用,返回的是一个方法对象,如果要调用这个方法,就可以用 test.get_Name() (注意,加了括号就是调用,不加就是方法对象)

            既然test2.get_Name是一个方法对象,那它就可以赋值给一个变量,用这个变量来调用该方法,如: 

            t = test2.get_name         # 赋值过程,赋值方法对象

            t()                                    #调用该方法

    3.5 类变量和实例变量

            简单来说,实例变量就是每个类的实例特有的变量,类变量就是类的各个实例所共享的变量,下面的这个例子很好的说明这个问题 :

        在上例中,通过构造函数__init__()来定义的变量就是实例变量,因为实例是通过类的构造函数来进行实例化的,而kind是定义类的时候定义的变量,是这个类的固有变量,叫类变量,类的每个实例都会共享这个类变量

4. 继承

    一个类继承另一个类,只是在类名后面多了一个要继承的类的字名,其余定义方法一样,格式如下:

    新定义的类叫衍生类(子类),被继承的这个类叫基类(父类)

    继承之后,子类可以直接调用父类中已经定义的方法,如果父类中方法不能满足要求时,在子类中可以重写这个方法,调用时,子类的方法要比父类的同名方法优先级要高,会优先被调用。

    子类中直接调用父类的方法:父类名.方法名(self, 参数)

    4.1 多态继承

           一个子类同时继承多个父类,格式如下:

        在多态继承中,子类调用父类方法的时候,先查找第一个父类(及其父类的父类的父类。。。)中方法,找不到的话再找第二个父类,以此类推

5. 私有实例变量

    私有实例变量是不能从类的外部直接接接触的变量,只能通过调用类的方法来获取或操作私有变量,这样的好处是保护数据的私密性,但在python中,真正意义上的私有变量是不存在的

    传统上,从代码格式的形式上来定义私有变量,在python中,以下划线开头的变量名被认为是私有变量,不应该从外部直接获取或修改(其实是可以的,只是这样定义)

6. 空类

    类似于c语言中的struct数据类型,可以定义一个空类把命名的数据绑定在一起存储起来,如下:

7. 迭代器

    使用 for 可以遍历迭代器中的每一个value, 原理如下:

    (1) for 调用 iter()方法作用在一个容器对象上,返回一下迭代器对象

    (2) 迭代器对象定义了__next__()方法,可以一次一个获取容器中元素

    (3) 当没有元素的时候,__next__() raise StoIteration 异常

    (4) for 接受到该异常信息而停止循环

    例子如下:

    通过定义__iter__ 和 __next__方法来自定义一个迭代器:

8. 生成器

    生成器是生成迭代器的一个有效的方式,可以定义函数的形式来创建生成器,只不过把return 改为关键字 yield, 如下:

    可以用生成器创建迭代器的,也都可以用基于类的方法通过实现__iter__和__next__方法来创建迭代器,但是生成器的方法会更简单一些,因为它已经自动创建了__iter__和__next__方法

9. 生成器表达式

    一些简单的生成器可以用类似列表推导式的方法来创建,但是要把列表推导式的中括号换成小括号    

    试用情况:生成器马上应用于一个闭合函数中

    特点:简洁,内存友好,不灵活

    如下例:

本篇内容较多,且不容易理解,新手可以先把数据结构以及常用的内置函数,概念掌握清楚再学习这一部分会好一些,详细请参考官方文档:https://docs.python.org/3/tutorial/classes.html

你可能感兴趣的:(Python官方教程阅读总结-类(Class))