Python面向对象语法精讲

Posted zach0812

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python面向对象语法精讲相关的知识,希望对你有一定的参考价值。

本专题的内容结构:

第一部分主要是:面向对象基础

第二部分主要是:面向对象进阶

    第一部分的结构:

        unit1:面向对象编程模式:

            (1),面向对象编程思想

            (2),面向对象的三个特征

            (3),Python面向对象术语

        unit2:Python类的构建:

            (1),类的基本构建

            (2),类的属性和方法

            (3),类的构造函数和析构函数

        unit3:实例1:银行ATM等待时间分析

            (1),对象的设计和构建

            (2),生活现象的程序分析

        unit4:Python类的封装

            (1),私有属性和公开属性

            (2),私有方法和公开方法

            (3),保留属性和保留方法

        unit5:Python类的继承:

            (1),子类,父类与超类

            (2),类的方法重载和属性重载

            (3),类的多继承   

    第二部分的结构:

        unit1:Python类的运算:

            (1),运算符的理解

            (2),各类运算符的重载

        unit2:Python类的多态:

            (1),多态的理解

            (2),参数类型的多态

            (3),参数形式的多态

        unit3:实例2:图像的四则运算

            (1),PIL库和Numpy 库实践

            (2),图像的加减乘除操作

        unit4:Python对象的引用

            (1),引用的理解

            (2),浅拷贝和深拷贝

        unit5:Python类的高级话题:

            (1),类的特殊装饰器

            (2),命名空间的理解

            (3),类的名称修饰

第一部分的内容:

    unit1:面向对象编程模式:

        (1),万物皆对象:

            自然意义上的对象:独立的存在 或 作为目标的事物

                >独立性:对象都存在清晰的边界,重点在于划分边界

                >功能性:对象都能表现出一些功能,操作或行为

                >交互性:对象之间存在交互,如:运算和继承

            Python语言的“万物皆对象”:

                >Python语言中所有数据类型都是对象,函数是对象,模块是对象

                >Python所有类都是继承于最基础类object

                >Python语言中数据类型的操作功能都是类方法的体现

        (2),面向对象编程思想:

            OOP :Object-Oriented Programming

                >OOP :面向对象编程,一种编程思想,重点在于高抽象的  复用代码

                >OOP 把对象当做程序的基本单元,对象包含数据和操作数据的函数

                >OOP 本质是把问题解决抽象为以对象为中心的计算机程序

                注:

                    >OOP在较大规模或复杂项目中十分有用,OOP可以提高协作产量

                    >OOP最主要的价值在于代码复用

                    >OOP只是一种编程方式,并非解决问题的高级方法

           

            面向过程    vs    面向对象

                >面向过程:以解决问题的过程步骤为核心编写程序的方式

                >面向对象:以问题对象构建和应用为核心编写程序的方式

                >所有OOP能解决的问题,面向过程都能解决

            小例子:

技术图片

技术图片

技术图片

 

 

        (3),面向对象的三个特征:

            OOP的三个特征:

                >封装:属性和方法的抽象,用数据和操作数据的方法来形成对象逻辑

                >继承:代码复用的高级抽象,用对象之间的继承关系来形成代码复用

                >多态:方法灵活性的抽象,让对象的操作更加灵活,更多复用代码

                        它能让更少的对象名称来支持更多的对象操作

               

                它们都是表达了代码抽象和代码复用,

           

            封装的理解:

                封装Encapsulation:属性和方法的抽象

                    >属性的抽象:对类的属性(变量)进行定义,隔离及保护

                    >方法的抽象:对类的方法(函数)进行定义,隔离及保护

                        >目标是形成一个类/对象  对外可操作属性和方法的接口

 

            继承的理解:

                继承 Inheritance:代码复用的高级抽象

                    >继承是面向对象程序设计精髓之一

                    >实现了以类为单位的高抽象级别代码复用

                    >继承是新定义的类 能够几乎完全使用原有类属性和方法的过程

           

            多态的理解:

                多态 Polymorphism :仅针对方法,方法灵活性的抽象

                    >参数类型的多态:一个方法能够处理多个类型的能力

                    >参数形式的多态:一个方法能够接受多个参数的能力

                    >多态是 OOP的一个传统概念,Python天然支持多态,不需要特殊语法

                            其他语言中要用特定的语法用多态,但是Python中设计的弱类型天然支持多态

               

                对多态的理解重点是概念和思路上的理解,更能理解Python对类的方法灵活性的抽象是如何表达的,

 

        (4),Python面向对象术语:

            先简要过一遍,后会介绍:

           

            类 Class 和 对象 Object :

                >类:逻辑抽象和产生对象的模板,一组变量和函数的特定编排

                >对象:具体表达数据及操作的实体,相当于程序中的"变量"

                >实例化:从类到对象的过程,所有"对象"都源于某个"类"

 

            对象: 对象具体分为: 类对象和实例对象

                类对象  vs   实例对象 :

                    >类对象:Class Object,当一个类建立之后,系统会维护个Python类基本信息的数据结构

                    >实例对象:Instance Object,Python类实例后产生的对象,简称:对象

                        >这是一组概念,类对象全局只有一个(保存类的基本信息),实例对象可以生成多个

 

 

 

            属性: 存储数据的“变量”,分为 :类属性 和实例属性

 

            方法: 操作数据的"函数",

                    包括:类方法,实例方法,自由方法,静态方法,保留方法

           

            三个特性:封装继承多态

 

            继承:基类,派生类,子类,父类,超类,重载

 

            命名空间:程序元素作用域的表达

 

            构造和析构:生成对象和删除对象的过程

 技术图片

 

 

        (5),Python面向对象实例入门:

            是上面的那个例子,计算价格的和,

            出现新的保留字class

                它可以定义抽象的Product 类,

技术图片
 1             class Product():
 2                 def __init__(self,name):
 3                     self.name = name
 4                     self.label_price = 0
 5                     self.real_price = 0
 6 
 7             c = Product("电脑")
 8             d = Product("打印机")
 9             e = Product("投影仪")
10             c.label_price,c.real_price = 10000,8000
11             d.label_price,d.real_price = 2000,1000
12             e.label_price,e.real_price = 1500,900
13             s1 ,s2 = 0,0
14             for i in [c,d,e]:
15                 s1+= i.label_price
16                 s2+= i.real_price
17             print(s1,s2)
View Code

 

 

 

 

 

    unit2:Python类的构建:

        python类的构建需要关注的地方:

就是上面的那个图:它包含了构建一个类所要关注的方方面面:

技术图片

 

(1),类的基本构建:

            使用class保留字定义类:

                class <类名>

                    [可以写个类描述字符串 "documentation string"]

                    <语句块>

                注:类定义不限位置,可以包含在分支或其他从属语句块中,执行时存在即可

                    可以放在全局部分,也可以放在分支,函数,等从属语句块中,由于Python 语言是脚本语言,

                    所以在某个对象引用之前,只要是类被定义就可以。

 

            类构造之类的名字:可以是任意有效标识符,建议采用大写单词的组合

                如:ClassName ,BasicAuto ,BasicCreature

 

 

            类构造之类描述:在类的定义后首行,以独立字符串形式定义

                定义可以通过 <类名>.__doc__ 属性来访问

                注:像这种前后都有两个下划线的属性是Python给类保留的属性,

                class DemoClass:

                    "This is a demo for Python class"

                    pass

 

                print(DemoClass.__doc__)

               

                >>>This is a demo for Python class

 

            介绍一个概念:类对象

                大家不要把类和对象拆开,类对象是一个名词,(Class Object

                    >类定义完成后,默认生成一个类对象

                        与其他语言不同,python的类只要定义完就会生成一个对象,但这个对象呢?只是与这个类唯一对应的,

                            每一个类只唯一对应一个类对象,这个类对象是存储这个类的基本信息的

                    >每个类唯一对应一个类对象,用于存储这个类的基本信息

                    >类对象是type类的实例,表达为type类型

                        什么是type类型呢?

                            它是编译器提供了一种类型,

                        class DemoClass:

                            "This is a demo for Python class"

                            print("hello DemoClass")

 

                        print(type(DemoClass))

                        输出:                       

                        hello DemoClass

                        <class ‘type‘>                    

 

                        我们发现,我们只是定义了这个类,但是它也执行 print("hello DemoClass)

                            这时因为在python中只要这个类被定义了, 就会生成一个表达它信息的 类对象

                            这个类对象是内置包含在类的定义中的,

                        那么这个类对象的生成使得类定义中的一些语句被执行,

                            因此,我们一般不在类的定义中直接包含语句,而是通过属性和方法来增加操作功能

                    类对象并不是使用类的常用方式,

 

                    使用类的方式最常用的是:通过创建实例对象来使用类的功能

                        <对象名> = <类名>([<参数>])

 

                        进一步采用 <对象名>.<属性名 <对象名>.<方法名>() 体现类的功能

 

                    实例对象的类型:

                       

                        它所生成时的那个类的类型

                        class DemoClass:

                            "This is a demo for Python class"

                            pass

                        print(type(DemoClass))

                        cn = DemoClass()

                        print(type(cn))

                        输出:

                        <class ‘type‘>

                        <class ‘__main__.DemoClass‘>

 

                        所以,实例对象和类对象是不一样的

                        实例对象是最常用的方式,

                   

                    了解Python 类的构造函数

                        >类的构造函数用于从类创建实例对象的过程

                        >类的构造函数为实例对象创建提供了参数输入方式

                        >类的构造函数为实例属性的定义和赋值提供了支持

 

                    了解Python类的属性和方法:

                        >类的属性:类中定义的变量,采用描述类的一些特性参数

                        >类的方法:类中定义且与类相关的函数,用来给出类的操作功能

                        >属性和方法是类对外交互所提供的两种接口方式

 

        (2),类的构造函数:

            类的构造函数是从类生成实例对象所使用的函数,

            Python中使用预定义的__init__() 作为构造函数,

                clsaa <类名>

                    def __init__(self,<参数列表>)

                        <语句块>

               

                类实例化时所使用的函数,可以接收参数并完成初始化操作

 

                class DemoClass:

                    def __init__(self,name):

                        print(name)

               

                dc1 = DemoClass("老王")

                dc2 = DemoClass("老李")

                输出: 

                    老王

                    老李

 

                注:通过构造函数__init__() 可以为Python对象提供参数

                还有,构造函数默认有个参数self ,它内部使用的,默认保留的,

 

                __init__() 的使用说明:

                    >参数:第一个参数约定是self,表示类实例自身,其他参数都是实例参数

                    >函数名:Python解释器内部定义的,由双下划线开始和结束

                    >返回值:构造函数没有返回值,或返回None ,否则产生TypeError 异常

               

                self 在类定义内部代表类的实例

                    >self Python面向对象中约定的一个类参数

                    >self代表类的实例,在类内部,self用于组合访问实例相关的属性和方法

                        >相比较而言,类名代表类对象本身

        (3),类的属性:

            属性是类内部定义的变量

                >类属性:类对象的属性,由所有实例对象共享

                >实例属性:实例对象的属性,由各实例所独享

 

            类的属性和实例属性是如何定义的?

            我们知道属性是变量,类中有两个地方可以放变量,

                第一个是在class 的全局命名空间:

                    <类属性名> =<类属性初值>

                第二个是在函数/方法中定义的它就是实例属性:

            class <类名>:

                <类属性名>=<类属性初值>

                def __init__(self,<参数列表>)

                    self.<实例属性名 > = <实例属性初值>

                ...

           

            class DemoClass:

                count = 0  #直接在类中定义或赋值 无论在类内类外,访问类属性都要用<类名>.<属性名>来访问

                def __init__(self,name,age):

                    self.name = name

                    self.age = age

                    DemoClass.count +=1

 

            dc1 = DemoClass("老王",45)

            dc2 = DemoClass("老李",51)

            print("总数:",DemoClass.count)

            print(dc1.name,dc2.name)

 

            我们已经知道,类属性在类内,类外都是<类名>.<类属性>

            而对于实例属性:

                在类内部,用self.<属性名>访问

                在类外部,用<对象名>.<属性名> 访问

 

            注:在类外,类属性也是可以用<对象名>.<属性名>来访问的       

            class DemoClass:

                def __init__(self,name):

                    self.name = name

                    #注:构造函数没有返回值

 

                def luckey(self):

                    s = 0

                    for c in self.name:

                        s+=ord(c)%100

                    return s

            dc1 = DemoClass("Wang")

            dc2 = DemoClass("Li")

 

            print(DemoClass.__dict__) # 类对象的属性字典

            print(dc1.__dict__)  # 实例对象的属性字典

            print(dc2.__dict__)  # 实例对象的属性字典

 

            print(DemoClass.__dir__(DemoClass)) #类对象的属性列表

            print(dc1.__dir__())           #实例对象的属性列表

 

 

        (4),类的方法:

            方法是类内部定义的函数:

                >实例方法:实例对象的方法,由各实例对象独享,最常用的形式

                >类方法:类对象的方法,由所有实例对象共享

                >自由方法:类中的一个普通函数,由类所在命名空间管理,类对象独享

                >静态方法:类中的一个普通函数,由类对象和实例对象共享

                >保留方法:由双下划线开始和结束的方法,保留使用,如__len__()

 

                方法1:实例方法:

                    实例方法是类内部定义的函数,与实例对象相关

                    class <类名>:

                        def <方法名>(self,<参数列表>):

                            ...

                    实例方法采用 <对象名>.<方法名>(<参数列表>) 方式使用

                    class DemoClass:

                        def __init__(self,name):

                            self.name = name

                            #注:构造函数没有返回值

 

                        def luckey(self):

                            s = 0

                            for c in self.name:

                                s+=ord(c)%100

                            return s

                    dc1 = DemoClass("Wang")

                    dc2 = DemoClass("Li")

 

                    print(dc1.name,"‘s lucky number is :",dc1.luckey())

                    print(dc2.name,"‘s lucky number is :",dc2.luckey())                                                                                                  

                    输出:

                    Wang ‘s lucky number is : 197

                    Li ‘s lucky number is : 81

                方法2:类方法:

                    类方法是与类对象相关的函数,由所有实例对象共享

                    class <类名>

                        @classmethod   装饰器

                        def <方法名>(cls,<参数列表>)

                            ...

                    类方法采用 <类名>.<方法名>(<参数列表>) <对象名>.<方法名>(<参数列表>) 方式使用

                        >类方法至少包含一个参数,表示类对象,建议使用cls

                        >@classmethod是装饰器,类方法定义必须要有

                        >类方法只能操作类属性和其他类方法,不能操作实例属性和实例方法

                        class DemoClass:

                            count =0

                            def __init__(self,name):

                                self.name = name

                                DemoClass.count +=1

                                #注:构造函数没有返回值

                            @classmethod

                            def getChrCount(cls):

                                s = "0123456789"

                                return s[DemoClass.count]

 

                        dc1 = DemoClass("Wang")

                        dc2 = DemoClass("Li")

                       

                        print(DemoClass.getChrCount())

                        print(dc1.getChrCount())  # 类方法是可以被实例对象调用的,因为它归类对象和实例对象共同所有

                        输出:

                        2

                        2

                方法3,自由方法:

                    是定义在类命名空间中的普通函数

                    class <类名>:

                        def <方法名>(<参数列表>):

                            ...

                            # 注:这里既没有self,也没有cls

 

                    自由方法采用 <类名>.<方法名>(<参数列表>)方式使用,这时的<类名>代表的是命名空间   

                        换句话说,自有方法是什么,它是在<类名>这个命名空间中定义的一个函数,访问它只能用

                            <函数名>.方法名  来访问,

 

                    注:类对象自己独有

                    >自由方法不需要self,cls这类参数,可以没有参数

                    >自由方法只能操作类属性和类方法,不能操作实例属性和实例方法

                    >自由方法的使用只能用<类名>

                    严格来说,自由方法就不应该算是方法,它就是个函数,只不过是定义在类的命名空间中

                        为了统一说法,所以我们叫它自由方法,

                         class DemoClass:

                            count =0

                            def __init__(self,name):

                                self.name = name

                                DemoClass.count +=1

                                #注:构造函数没有返回值

                            def func():

                                DemoClass.count *=100

                                return DemoClass.count

 

                        dc1 = DemoClass("Wang")

                        print(DemoClass.func())

                        输出: 100

                方法4:静态方法:

                    我们知道,自由方法只能由类对象来使用,有没有办法让实例对象使用普通的函数(没有self,cls)呢?

                    可以,就是在自由方法的基础上加上一个装饰器@classmethod就可以了,

                    它是定义在类中的普通函数,能够被所有实例对象共享

                        class <类名>:

                            @staticmethod

                            def <方法名>(<参数列表>):

                                ...

                        静态方法采用 <类名>.<方法名>(<参数列表>) <对象名>.<方法名>(<参数列表>) 方式使用

                    >静态方法可以没有参数,可以理解为定义在类中的普通函数

                    >@staticmethod是装饰器,静态方法必须用它

                    >静态方法只能操作 类属性和其他类 方法,不能操作实例属性和实例方法

                    >相比于自由方法,静态方法能够使用<类名><对象名>两种方式调用

                   

                    class DemoClass:

                        count =0

                        def __init__(self,name):

                            self.name = name

                            DemoClass.count +=1

                            #注:构造函数没有返回值

                        @staticmethod

                        def func():

                            DemoClass.count *=100

                            return DemoClass.count

 

                    dc1 = DemoClass("Wang")

                    print(dc1.func())

                    print(DemoClass.func())

 

                    记时,方法3和方法4一起记

                方法5:保留方法:

                    保留方法由双下划线开始和结束的方法,保留使用

                        class <类名>:

                            def <保留方法名>(self,<参数列表>)

                                ...

                        保留方法一般都对应类的某种操作,使用操作符调用它

                   

                    其实构造函数本身也是保留方法,

                        class DemoClass:

                            count =0

                            def __init__(self,name):

                                self.name = name

                                DemoClass.count +=1

                                #注:构造函数没有返回值

 

                            def __len__(self):

                                return len(self.name)

 

                        dc1 = DemoClass("Wang")

                        print(len(dc1))

                        输出:4

 

                        __len__ () 方法对应内置函数len() 函数操作

                        理解:

                            这时Python 解释器保留方法,已经对应,只需要编写代码即可

                       

                        重写保留方法:

                        class DemoClass:

                            count =0

                            def __init__(self,name):

                                self.name = name

                                DemoClass.count +=1

                                #注:构造函数没有返回值

 

                            def __len__(self):

                                return 5

                        dc1 = DemoClass("Wang")

                        print(len(dc1))

                        输出: 5

 

                        终结总结:

                            我们可以理解为len() 只能计算基本数据类型的长度,对于类的长度它不能计算

                            我们就让他去调用类的保留方法__len__() 

                           

                            len(dc1)  其实它还是调用的是dc1.__len__() 方法

                                然后:这个保留方法内部计算了一个基础类型的长度 len(name)

        (5),类的析构函数:

            当一个对象不用的时候,我们要对它释放空间,

            Python使用预定义的__del__() 作为析构函数

                class <类名>

                    def __del__(self):

                        <语句块>

                        ...

                析构函数在“真实” 删除实例对象时被调用

                “真实”后面会介绍

            例子:

            class DemoClass:

                def __init__(self,name):

                    self.name = name

 

                def __del__(self):

                    print("再见",self.name)

 

            dc1 = DemoClass("Wang")

            del dc1

            输出:

            再见 Wang

           

            删除对象就是使用保留字del 

            使用del 删除对象且对象被真实删除 时调用析构函数__del__()

 

            >函数名和参数:Python解释器内部约定,保留方法

            >调用条件:当实例对象被“真实删除”时,才调用该函数语句

            >“真实删除”:当前对象的引用数为0 或当前程序退出(垃圾回收)

            例子:

                import  time

                class DemoClass:

                    def __init__(self,name):

                        self.name = name

 

                    def __del__(self):

                        print("再见",self.name)

 

                dc1 = DemoClass("Wang")

                dc2 = dc1  #引用

 

                del dc1

                print(dc2.name)

 

                while(True):

                    time.sleep(1)  # 使程序不退出

                输出:

                Wang

               

                这就是只有当真实删除时才会调用析构函数

 

            当然,一般构建对象的时候,我们不用写析构函数,python的垃圾回收机制已经很灵活了。

 

           

            Python类的内存管理:

                >在删除对象前,Python解释器会检查引用次数

                >检查删除之后是否引用次数为0,不为0则仅删除当前引用;为0,则删除对象

                >如果程序退出,则由垃圾回收机制删除对象

            那么如何对一个对象的引用数量进行获取呢?

                python 提供了一个sys.getrefcount(<对象名>)获得对象的引用次数

                >返回对象引用次数的方法,辅助删除对象时的分析

                >sys.getrefcount() 函数返回值为 引用值 +1

                >非特定目的,不建议自己写析构函数,利用Python垃圾回收机制就行

                import sys

                class DemoClass:

                    def __init__(self,name):

                        self.name = name

 

                    def __del__(self):

                        print("再见",self.name)

 

                dc1 = DemoClass("Wang")

                dc2 = dc1  #引用

 

                print(sys.getrefcount(dc1))

                输出: 3  (比真实多1)

 

    unit3:实例1:银行ATM等待时间分析:

        需求分析:

   技术图片

 

可扩展为泊松分布:

技术图片

 

技术图片
 1         import random as rd
 2         ‘‘‘
 3         整体思路:
 4             1,需要一个全局时间
 5             2,以ATM每次处理结束的时间为时间驱动事件
 6             3,需要一个等待队列,维护客户到达时间
 7             4,时间变化时,驱动等待队列变化
 8         ‘‘‘
 9         class ATM():
10             def __init__(self,maxtime = 5):
11                 self.t_max = maxtime
12             def getServCompleteTime(self,start= 0):#完成一次业务的时间 start 可赋值给真实的时间,
13                                                     # 这样就是绝对的时间了
14                 return start + rd.randint(1,self.t_max)
15 
16         class Customers():
17             def __init__(self,n):
18                 self.count = n
19                 self.left = n
20             def getNextArrvTime(self,start = 0,arrvtime = 10): #下一个人到达的时间
21                 if self.left !=0:
22                     self.left -=1
23                     return start +rd.randint(1,arrvtime)
24                 else:
25                     return 0
26             def isOver(self): #判断n 个客户是否都到达了
27                 return True if self.left == 0 else False
28 
29         c = Customers(100) #100个客户
30         a = ATM()
31         wait_list =[] #存放用户到达时间
32         wait_time =0 #总共等待时间
33         cur_time= 0 #当前时间
34         cur_time +=c.getNextArrvTime()
35         wait_list.append(cur_time)
36         while len(wait_list) !=0 or not c.isOver():
37             if wait_list[0] <= cur_time: # 用户提前到了
38                 next_time = a.getServCompleteTime(cur_time) #下次时间
39                 del wait_list[0]
40             else:
41                 next_time = cur_time +1
42 
43             if not c.isOver() and len(wait_list) ==0:
44                 next_arrv = c.getNextArrvTime(cur_time)
45                 wait_list.append(next_arrv)
46 
47             if not c.isOver() and wait_list[-1] <next_time:
48                 next_arrv = c.getNextArrvTime(wait_list[-1])
49                 wait_list.append(next_arrv)
50                 while not c.isOver() and next_arrv <next_time:
51                     next_arrv = c.getNextArrvTime(wait_list[-1])
52                     wait_list.append(next_arrv)
53             for i in wait_list:
54                 if i<= cur_time:
55                     wait_time += next_time -cur_time
56                 elif cur_time <i <next_time:
57                     wait_time += next_time -i
58                 else:
59                     pass
60                 cur_time = next_time
61         print(wait_time/c.count)
View Code

 

 技术图片

unit4:Python类的封装  

        (1),封装的理解:

            封装Encapsulation :属性和方法的抽象

                > 属性的抽象:对类的属性(变量)进行定义,隔离及保护

                > 方法的抽象:对类的方法(函数)进行定义,隔离及保护

                    >目的是形成一个类对外可操作属性和方法的接口

            类中有属性和方法:

                而属性和方法又封装了一些:

               

                属性:

                    >分为私有属性:只能在类内部访问

                    >公开属性:可以通过类/对象名访问

                方法:

                    >私有方法:只能在类内部使用

                    >公开方法:可以通过类/对象名访问

            >属性的抽象:可以选择公开或隐藏属性,隐藏属性的内在机理

            >方法的抽象:可以选择公开或隐藏方法,隐藏方法的内部逻辑

            >封装:让数据和代码成为类的过程,表达为: -属性-方法

 

        (2),私有属性和公开属性:

            对于类来说,有类对象和实例对象

            所以,属性共有四类:

                >公开类属性

                >私有类属性

                >公开实例属性

                >私有实例属性

           

            1,公开类属性:即类属性

                class <类名>:

                    <类属性名> =<类属性初值>

                    def __init__(self,<参数列表>):

                        ...

            2,私有类属性:

                仅供当前类访问的类属性,子类也不可访问

                class   <类名>:

                    <私有类属性名> =<类属性初值>

                    def __init__(self,<参数列表>):

                        ...

                区别:私有类属性名开始需要有两个下划线,__count

               

                >只能在类的内部被方法所访问

                >不能通过<类名>.<属性名><对象名>.<属性名>方式访问

                >有效保证了属性维护的可控性

                    class DemoClass:

                        __count = 0

                        def __init__(self,name):

                            self.name = name

                            DemoClass.__count += 1

 

                        @classmethod

                        def getCount(cls):

                            return DemoClass.__count

 

                    dc1 = DemoClass("Wang")

                    dc2 = DemoClass("Li")

                    print(DemoClass.getCount())

                    输出:2

            3,公开实例属性:即实例属性

                class <类名>:

                    <类属性名> =<类属性初值>

                    def __init__(self,<参数列表>)

                        self.<实例属性名> = <实例属性初值>

                        ...

            4,私有实例属性:仅供当前类内部访问的实例属性,子类也不能访问

                class <类名>:

                    <类属性名> =<类属性初值>

                    def __init__(self,<参数列表>)

                        self.<私有实例属性名> = <实例属性初值>    

                注:方法一样,加上双下划线

                >只能在类的内部被方法所访问

                >不能通过<类名>.<属性名><对象名>.<属性名>方式访问

                >有效保证了属性维护的可控性

                例子:

                    class DemoClass:

                        def __init__(self,name):

                            self.__name = name

 

                        def getName(self):

                            return self.__name

 

                    dc1 = DemoClass("Wang")

                    dc2 = DemoClass("Li")

                    print(dc1.getName(),dc2.getName())

            多看一眼:私有属性

                双下划綫方法只是一种转换约定,转换后,类内原有名字发生了变化

                这是一种形式上的私有!

                它并不是真正的安全

                class DemoClass:

                    def __init__(self,name):

                        self.__name = name

 

                    def getName(self):

                        return self.__name

 

                dc1 = DemoClass("Wang")

                dc2 = DemoClass("Li")

                print(dc1._DemoClass__name)

                输出: wang 

                这说明所谓的私有属性并不是真正的私有,只不过要换个名字才能访问它,这里的名字是

                    _DemoClass__name

               

                这是形式上私有  

                别的语言(c++),是真正的私有

 

               

 

        (3),私有方法和公开方法:

            我们知道类有五种方法:

                >实例方法

                >类方法

                >自由方法

                >静态方法

                >保留方法

           

            私有方法是类内部定义并使用的函数:

                class <类名>:

                    def <方法名>(self,<参数列表>):

                        ...

                私有方法名开始需要有两个下划线,如 __getCount()

               

                    class DemoClass:

                        def __init__(self,name):

                            self.__name = name

 

                        def __getName(self):

                            if self.__name != "":

                                return self.__name

                            else:

                                return "Zcb"

                        def printName(self):

                            return "同志".format(self.__getName())

                       

                    dc1 = DemoClass("Wang")

                    dc2 = DemoClass("")

                    print(dc1.printName(),dc2.printName())

                    输出:Wang同志 Zcb同志

                >各类方法都可以通过增加双下划线变为私有方法

                >私有方法从形式上保护了Python类内部使用的函数逻辑

                >私有与公开是程序员逻辑,不是安全逻辑,重视约定

                    class DemoClass:

                        def __init__(self,name):

                            self.__name = name

 

                        def __getName(self):

                            if self.__name != "":

                                return self.__name

                            else:

                                return "Zcb"

                        def printName(self):

                            return "同志".format(self.__getName())

 

                    dc1 = DemoClass("Wang")

                    dc2 = DemoClass("")

 

                    print(dc1._DemoClass__getName())

                    输出: Wang

                私有方法是一种形式上的私有,   

        (4),类的保留属性:

            Python 解释器预留了一些类的属性,以双下划线开头和结尾来表示

            >也叫:特殊属性,Special Attributes

            >特点:双下划线开头和结尾

            >作用:为理解Python类提供了同一的属性接口

            >属性值:具有特定含义,类定义后直接使用

           

            1,仅用 <类名> 访问的保留属性:

                >__name__  : 类的名称

                >__qualname__ : .分隔从模块全局命名空间开始的类名称

                >__bases__ :类所继承的基类名称

                例子:

                    class DemoClass:

                        "A Demo Class"

                        def __init__(self,name):

                            self.__name = name

                        def getName(self):

                            return self.name

                    dc1 = DemoClass("Wang")

 

                    print(DemoClass.__qualname__,DemoClass.__name__,DemoClass.__bases__)

                    输出:

                    DemoClass DemoClass (<class ‘object‘>,)

                        由于当前类是定义在类的全局命名空间中,所以第二个就只是DemoClass

                    如下:将一个类定义在函数中:

                    def func():

                        class DemoClass:

                            "A Demo Class"

                            def __init__(self,name):

                                self.__name = name

 

                            def getName(self):

                                return self.name

                        return DemoClass

 

                    DemoClass =func()

 

                    dc1 = DemoClass("Wang")

 

                    print(DemoClass.__qualname__,DemoClass.__name__,DemoClass.__bases__)

                    输出:

                    func.<locals>.DemoClass DemoClass (<class ‘object‘>,)

            2,其他的保留属性:

                <>.__dict__  包含类 成员(属性和方法) 信息的字典,key 是属性和方法名称,value是地址

                <对象>.__dict__ 包含对象属性信息的字典,key是属性名称,value 是值

                __class__  :对象所对应的类信息,即type信息

                __doc__  : 类描述,写在类定义下的首行字符串,不能继承

                __module__ :类所在模块的名称

                class DemoClass:

                    "A Demo Class"

                    def __init__(self,name):

                        self.__name = name

 

                    def getName(self):

                        return self.name

 

                dc1 = DemoClass("Wang")

 

                print(DemoClass.__doc__,DemoClass.__module__,DemoClass.__class__)

                print(dc1.__doc__,dc1.__module__,dc1.__class__)

                输出:

                    A Demo Class __main__ <class ‘type‘>

                    A Demo Class __main__ <class ‘__main__.DemoClass‘>

                    注: 类对象的类是type

                         实例对象的类时__main__.DemoClass

                class DemoClass:

                    "A Demo Class"

                    def __init__(self,name):

                        self.__name = name

 

                    def getName(self):

                        return self.name

 

                dc1 = DemoClass("Wang")

 

                print(DemoClass.__dict__)

                print(dc1.__dict__)

                输出:

                    ‘__dict__‘: <attribute ‘__dict__‘ of ‘DemoClass‘ objects>, ‘getName‘: <function DemoClass.getName at 0x00000208D8084B70>, ‘__init__‘: <function DemoClass.__init__ at 0x00000208D8084510>, ‘__module__‘: ‘__main__‘, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘DemoClass‘ objects>, ‘__doc__‘: ‘A Demo Class‘

                    ‘_DemoClass__name‘: ‘Wang‘

        (5),类的保留方法:

            与保留属性类似,python解释器预留 类的保留方法

                它们以双下划线开头和结尾

            >也叫:特殊方法,Special Methods

            >特点:双下划线开头和结尾

            >作用:为操作Python类提供了统一的方法接口

            >方法逻辑:具有特定含义,一般与操作符关联,类定义需要重载

                Python解释器只是预留了这些名字,但是并没有预留逻辑,预留逻辑需要我们自己写,

 

            常用保留方法:基础类别

                保留方法            对应操作                 描述

                obj.__init__()     obj = ClassName()    初始化实例对象的函数逻辑

                obj.__del__()      del obj              删除实例对象的函数逻辑

                obj.__repr__()     repr(obj)            定义对象可打印字符串的函数逻辑

                obj.__str__()      str(obj)             定义对象字符串转换操作的函数逻辑

                obj.__del__()      del obj              删除实例对象的函数逻辑

                如何理解:str(obj)  obj 是个对象,

                    那么它的str是什么呢?这就可以在其内部的__str__()中来定义函数逻辑了

                    其他依次类推

                obj.__bytes__()      bytes(obj)             定义对象字节串转换操作的函数逻辑

                obj.__format__()     format(obj)            定义对象格式化输出的的函数逻辑

                obj.__hash__()       hash(obj)              定义对象哈希操作的函数逻辑

                obj.__bool__()       bool(obj)              定义对象布尔运算的函数逻辑

               

                obj.__len__()        len(obj)               定义对象长度操作的函数逻辑

                obj.__reversed__()   obj.reversed()         定义对象逆序的函数逻辑

                obj.__abs__()        abs(obj)               定义对象绝对值操作的函数逻辑

                obj.__int__()        int(obj)               定义对象整数转换的函数逻辑

            常用保留方法:比较操作

                保留方法            对应操作                 描述

                obj.__lt__()       obj1<obj2              对象间比较操作的保留方法

                obj.__le__()       obj1<=obj2              对象间比较操作的保留方法

                obj.__eq__()       obj1==obj2              对象间比较操作的保留方法

                obj.__ne__()       obj1!=obj2              对象间比较操作的保留方法

                obj.__gt__()       obj1>obj2              对象间比较操作的保留方法

                obj.__ge__()       obj1>=obj2              对象间比较操作的保留方法

                    小于: little 大于是:great 等于:equal

               

                同样的是,关于两个对象如何去比较,这是需要我们自己在其中补充代码   

 

            Python 类保留方法使用说明:

                >Python保留了超过100个各种保留方法

                >保留方法对应对象,对象间,对象方法的各种操作

                >有哪些保留方法? 请参考各种数据类型的使用

        总结: python 并不支持天然的私有封装,所谓的私有只是一种形式上的私有

 

 

    unit5:Python类的继承:

        (1),继承的理解:

            继承 Inheritance :它是代码复用的高级抽象

            >继承是面向对象的设计精髓之一

            >实现了以类为单位的高抽象级别代码复用

            >继承是新定义的类能够几乎完全使用原有类属性与方法的过程

           

            之所以,使用面向对象是因为它比函数能提供更高级别的代码复用能力,

 技术图片  (基类和派生类只是两种说法,它们都是Python类)

 

            除了基类和派生类,还有子类,父类,超类

技术图片

 

            最后生成的那个派生类是子类,子类直接继承的是父类,间接继承的是超类,

                这些只是一些定义,

           

            在讲派生时,我们一般用基类和派生类  父类和子类, 都可以的,

 

            同时,派生类也可以继承多个基类,这就是多继承问题,

技术图片

 

        (2),类继承的构建:

            在定义类时声明继承关系

                calss <类名> (<基类名>):

                    def __init__(self,<参数列表>):

                        <语句块>

                    ...

                基类名也可以带有路径: MoudleName.BaseClassName

 

                注:一定要记住,类名后的括号不是参数列表而是继承

           

            派生类(子类) 可以直接使用基类(父类)的属性和方法:

                >父类的属性 基本等同于 定义在子类中

                >子类可以直接使用父类的类属性,实例属性

                >子类可以直接使用父类的各种方法

                >使用父类的类方法和类属性时,要用父类的类名调用

                例子:

                    class DemoClass:

                        count = 0

                        def __init__(self,name):

                            self.name = name

                            DemoClass.count += 1

                        def getName(self):

                            return self.name

 

                    class HumanNameClass(DemoClass):

                        def printName(self):

                            return str(DemoClass.count)+self.name +"同志"

 

                    dc1= HumanNameClass("Wang")

                    print(dc1.getName())

                    print(dc1.printName())

                    输出:

                        Wang

                        1Wang同志

 

                    注意:父类的属性和方法相当于定义在子类中

           

            2个与继承关系判断有关的Python内置函数:

                isinstance(obj,cls)  判断对象obj 是否是类cls 的实例或子类实例,返回True/False

                issubclass(cls1,cls2)判断类cls1 是否是类cls2 的子类,返回True/False

                例子:

                    class DemoClass:

                        count = 0

                        def __init__(self,name):

                            self.name = name

                            DemoClass.count += 1

                        def getName(self):

                            return self.name

 

                    class HumanNameClass(DemoClass):

                        def printName(self):

                            return str(DemoClass.count)+self.name +"同志"

 

                    dc1= HumanNameClass("Wang")

 

                    print(isinstance(dc1,DemoClass))

                    print((isinstance(dc1,HumanNameClass)))

                    print(issubclass(HumanNameClass,DemoClass))

                输出:

                    True             

                    True             

                    True   

            子类的约束:

                >子类只能继承基类的公开属性和方法

                >子类不能继承父类的私有属性和私有方法

 

        (3),Python最基础类:

            object类时Python所有类的基类

            >objectPython最基础类的名字,不建议翻译理解,类的名字就是object (o是小写)

            >所有类定义时默认继承object

            >保留属性和保留方法本质上是object类的属性和方法,因为我们定义的任何类都继承object,

                所以object里的保留属性和方法就成了任何类中可用的属性和方法了

           

            我们通过object的保留属性和保留方法来了解object

                print(object.__name__)

                print(object.__doc__)

                print(object.__bases__)

                print(object.__class__)

                print(object.__module__)

                print(object.__dict__)

 

                输出:

                    object

                    The most base type

                    () #它本身就是基类

                    <class ‘type‘> #因为object是类对象,类对象都是type 类型

                    builtins

                    ‘__ne__‘: <slot wrapper ‘__ne__‘ of ‘object‘ objects>, ‘__new__‘: <built-in method __new__ of type object at 0x0000000058BFDFD0>, ‘__repr__‘: <slot wrapper ‘__repr__‘ of ‘object‘ objects>, ‘__reduce__‘: <method ‘__reduce__‘ of ‘object‘ objects>, ‘__init__‘: <slot wrapper ‘__init__‘ of ‘object‘ objects>, ‘__delattr__‘: <slot wrapper ‘__delattr__‘ of ‘object‘ objects>, ‘__eq__‘: <slot wrapper ‘__eq__‘ of ‘object‘ objects>, ‘__str__‘: <slot wrapper ‘__str__‘ of ‘object‘ objects>, ‘__ge__‘: <slot wrapper ‘__ge__‘ of ‘object‘ objects>, ‘__doc__‘: ‘The most base type‘, ‘__format__‘: <method ‘__format__‘ of ‘object‘ objects>, ‘__le__‘: <slot wrapper ‘__le__‘ of ‘object‘ objects>, ‘__sizeof__‘: <method ‘__sizeof__‘ of ‘object‘ objects>, ‘__subclasshook__‘: <method ‘__subclasshook__‘ of ‘object‘ objects>, ‘__reduce_ex__‘: <method ‘__reduce_ex__‘ of ‘object‘ objects>, ‘__setattr__‘: <slot wrapper ‘__setattr__‘ of ‘object‘ objects>, ‘__lt__‘: <slot wrapper ‘__lt__‘ of ‘object‘ objects>, ‘__hash__‘: <slot wrapper ‘__hash__‘ of ‘object‘ objects>, ‘__gt__‘: <slot wrapper ‘__gt__‘ of ‘object‘ objects>, ‘__getattribute__‘: <slot wrapper ‘__getattribute__‘ of ‘object‘ objects>, ‘__class__‘: <attribute ‘__class__‘ of ‘object‘ objects>, ‘__dir__‘: <method ‘__dir__‘ of ‘object‘ objects>

           

            还有要知道

                Python里的对象都有三个要素:标识,类型,和值

                >标识identity :对象一旦构建不会改变,用id() 获得,一般是内存地址

                >类型type : 对象的类型,用type()获得

                > value :分为可变mutable 和不可变 immutable 两种

           

            2个与基础类有关的Python内置功能:

                函数/保留字         描述

                id(x)           返回x 的标识,Cpython用内存地址标识

                x is y          判断x y 的标识是否相等,返回 True/False,不判断值

                例子:

                    class DemoClass:

                        count = 0

                        def __init__(self,name):

                            self.name = name

                            DemoClass.count += 1

                        def getName(self):

                            return self.name

 

                    class HumanNameClass(DemoClass):

                        def printName(self):

                            return str(DemoClass.count)+self.name +"同志"

 

                    dc1= HumanNameClass("Wang")

                    print(id(dc1),type(dc1))

                    print(id(DemoClass),type(DemoClass))

                    print(dc1 is DemoClass)

                    print(type(object),type(type))

                输出:

                    2625484754056 <class ‘__main__.HumanNameClass‘>

                    2625483867848 <class ‘type‘>  #类对象的地址和类对象的类型type

                    False

                    <class ‘type‘> <class ‘type‘> #这说明最基础的类型是type 而最基础的类是object

            总结:

技术图片

 

                       

 

           

 

 

 

 

 

        (4),类的属性重载:

            重载是指子类对父类属性或方法的再定义

                >属性重载:子类定义并使用了与父类相同名称的属性

                >方法重载:子类定义并使用了与父类相同名称的方法

            最近覆盖原则:

                重载无序特殊标记

                >步骤1:优先使用子类重定义的属性和方法

                >步骤2:然后寻找父类的属性和方法

                >步骤3:再寻找超类的属性和方法

                例子:

                    class DemoClass:

                        count = 0

                        def __init__(self,name):

                            self.name = name

                            DemoClass.count += 1

                        def getName(self):

                            return self.name

 

                    class HumanNameClass(DemoClass):

                        count = 99

                        def __init__(self,name):

                            self.name = name

                            HumanNameClass.count -=1

                        def printCount(self):

                            return str(HumanNameClass.count)+self.name

 

                    dc1= HumanNameClass("Wang")

                    print(dc1.printCount())

                    输出:

                        98Wang

        (5),类的方法重载:

            方法重载: 子类定义并使用了与父类相同名称的方法

                >完全重载:子类完全重定义与父类相同名称的方法

                    直接在类中定义同名方法即可

                >增量重载:子类扩展定义与父类相同名称的方法

           

            我们这里主要说增量重载:(因为完全重载太简单了)

                增量重载:使用super() 方法

                    class <子类名> (<父类名>):

                        def <方法名>(self,<参数列表>):

                            super().<父类方法名>(<参数列表>)

                            ...

                   

                    就是super() 函数实际上返回的是子类对应的父类

 

                    例子:

                        class DemoClass:

                            count = 0

                            def __init__(self,name):

                                self.name = name

                                DemoClass.count += 1

                            def printCount(self):

                                return str(HumanNameClass.count)+self.name

 

                        class HumanNameClass(DemoClass):

                            def __init__(self,name):

                                self.name = name

                            def printCount(self):

                                return super().printCount()+"同志"

 

                        dc1= HumanNameClass("Wang")

                        print(dc1.printCount())

                        输出:

                        0Wang同志  #这就给后面加上了同志二字

 

        (6),类的多继承: 

            多继承是指在定义类时,继承多个父类

            class <类名>(<父类名1>,<父类名2>,):

                def __init__(self,<参数列表>):

                    <语句块>

                ...

            注: 基类名也可以带有路径:MoudleName.BaseClassName

 

            Python3 采用深度优先,从左至右  的方法实施多继承

            例子:

                class DemoClass:

                    def __init__(self,name):

                        self.name = name

                    def printName(self):

                        return self.name

                   

                class NameClass:

                    def __init__(self,title):

                        self.nick = title

                    def printName(self):

                        return self.nick   + "同志"

 

                class HumanNameClass(DemoClass,NameClass):

                    pass

 

                dc1= HumanNameClass("Wang")

 

                print(dc1.printName())

                print(HumanNameClass.__mro__) #解析顺序MRO  是个元组

                输出:

                    Wang

                    (<class ‘__main__.HumanNameClass‘>, <class ‘__main__.DemoClass‘>, <class ‘__main__.NameClass‘>, <class ‘object‘>)

                注: MRO:Method Resolution Order,即方法解析顺序,是python中用于处理二义性问题的算法

                可通过<类名>.__mro__ 查看

            类多继承的使用说明:

                >所有属性和方法的使用按照 "深度优先,从左到右"的方式选取

                >构造函数也参数上述原则,super() 也参照上述原则

                >多个基类的顺序是关键

 

                例子:

                    class DemoClass:

                        def __init__(self,name):

                            self.name = name

                        def printName(self):

                            return self.name

 

                    class NameClass:

                        def __init__(self,title):

                            self.nick = title

                        def printName(self):

                            return self.nick   + "同志"

 

                    class HumanNameClass(DemoClass,NameClass):

                        def printName(self):

                            return super().printName() +"你好"

 

 

                    dc1= HumanNameClass("Wang")

 

                    print(dc1.printName())

                    输出:

                        Wang你好

 

第二部分的内容:

    unit1:Python类的运算:

        (1),运算符的理解:

            运算Operation :操作逻辑的抽象

                >运算体现一种操作逻辑,广义角度,任何程序都被认为是运算

                >Python解释器通过保留方法预留了一批运算的接口,需要重载

                >保留方法一般对应运算符,Python中运算体现为运算符的重载

 

                类有 算术运算

                    比较运算

                    成员运算

                    其他运算

 

                运算本质上体现了 交换关系

                         体现了 包含关系

                         体现了 常规关系

            运算重载的限制:

                >不能重载Python语言内置类型的运算符 ,比如改变字典类型的加法运算,这是不行的

                >不能新建运算符,只能通过重载完成

                >is  and  not  or 不能被重载

 

 

        =====各类运算符的重载

        (2),算术运算的重载:

            >一元算术运算符:+ - ~

            >二元算术运算符:+,-,*,/,//,%,divmmod(),pow(),**,<<,>>,&,^,|

 

            先看一元算术运算符的重载:

                保留方法            对应操作                 描述

                .__neg__(self)      -obj            定义对象取负的运算逻辑

                .__pos__(self)      +obj            定义对象取正的运算逻辑

                .__abs__(self)      abs(obj)        定义对象取绝对值的运算逻辑

                .__invert__(self)   ~obj            定义对象取反的运算逻辑

            二元算术运算符的重载:

                保留方法                对应操作                 描述

                .__add__(self,other)  obj +other        定义两个对象加法的运算逻辑

                .__sub__(self,other)  obj -other        定义两个对象减法的运算逻辑

                .__mul__(self,other)  obj *other        定义两个对象乘法的运算逻辑

                .__truediv__(self,other)  obj /other    定义两个对象除法的运算逻辑

                .__floordiv__(self,other)  obj //other  定义两个对象整除的运算逻辑

                .__mod__(self,other)  obj %other        定义两个对象模的运算逻辑

                .__divmod__(self,other) divmod(obj,other)定义两个对象除模的运算逻辑

 

                .__pow__(self,other)  obj **other       定义两个对象幂的运算逻辑

                .__lshift__(self,other)  obj <<other    定义两个对象左移的运算逻辑

                .__rshift__(self,other)  obj >>other    定义两个对象右移的运算逻辑

 

                .__and__(self,other)  obj &other       定义两个对象位与的运算逻辑

                .__xor__(self,other)  obj ^other       定义两个对象位异或的运算逻辑

                .__or__(self,other)   obj |other       定义两个对象位或的运算逻辑

            例子:

                class myList(list):  # 继承list 类

 

                    def __add__(self, other): #重载加法运算

                        result =[]

                        for i in range(len(self)):

                            try:

                                result.append(self[i]+other[i])

                            except:

                                result.append(self[i])

                        return result

 

                ls1 = myList([1,2,3,4,5,6])

                ls2 = myList([1,5,6,8])

                print(ls1+ls2) 

                输出:

                    [2, 7, 9, 12, 5, 6]

 

                注:

                    ls3=[1,5,66]

                    ls4=[1,2]

                    print(ls3+ls4)

                    输出:[1, 5, 66, 1, 2]

 

        (3),比较运算的重载:

            >比较运算:<,<=,==,!=,>,>=  六种比较运算

                保留方法            对应操作                 描述

                obj.__lt__()       obj1<obj2              对象间比较操作的保留方法

                obj.__le__()       obj1<=obj2              对象间比较操作的保留方法

                obj.__eq__()       obj1==obj2              对象间比较操作的保留方法

                obj.__ne__()       obj1!=obj2              对象间比较操作的保留方法

                obj.__gt__()       obj1>obj2              对象间比较操作的保留方法

                obj.__ge__()       obj1>=obj2              对象间比较操作的保留方法

                    小于: little 大于是:great 等于:equal

                例子: 

                    class myList(list):  # 继承list 类

                        def __lt__(self, other):

                            "以各元素的算术和为比较依据"

                            s,t = 0,0

                            for c in self:

                                s +=c

                            for c in other:

                                t +=c

                            return True if s<t else False

                    ls1 = myList([1,2,3,4,5,6])

                    ls2 = myList([1,5,6,8])

                    print(ls1<ls2)

                    输出:

                        False

                    注:

                        ls3 = [1,2,3,4,5,6]

                        ls4 = [1,5,6,8]

                        print(ls3<ls4)

                    输出:

                        True

                   

 

        (4),成员运算的重载:

            成员运算的种类:

                >成员获取:[],del ,.reversed()

                >成员判断: in, not in

            先看成员获取:

                保留方法                    对应操作                 描述

                .__getitem__(self,key)   obj[k]               定义获取对象中序号k元素的运算逻辑,k为整数

                .__setitem__(self,key,v) obj[k] =v            定义赋值对象中序号k元素的运算逻辑,k为整数

                .__delitem__(self,key)   del obj[k]           定义删除对象中序号k元素的运算逻辑,k为整数

                .__reversed__(self)      obj[k]               定义对象逆序的运算逻辑

           

            成员判断:

                保留方法                    对应操作                 描述

                .__contains__(self,item)   item in obj        定义in 操作符对应的运算逻辑

                #not in不能重载 ,因为not 不能被重载

            例子: 

                class myList(list):  # 继承list 类

                    def __contains__(self, item):

                        "各元素的算术和也作为成员"

                        s =0

                        for c in self:

                            s +=c

                        if super().__contains__(item) or item ==s:

                            return True

                        else:

                            return False

 

                ls = myList([6,1,2,3])

                print(6 in ls ,12 in ls)

                输出:

                    True True

        (5),其他运算的重载:

            其他运算:

                >Python内置函数:repr(),str(),len(),int(),float(),

                    complex(),round(),bytes(),bool(),format()

                >类的常用方法:.format()

 

                保留方法            对应操作                 描述

                .__repr__()     repr(obj)            定义对象可打印字符串的运算逻辑

                .__str__()      str(obj)             定义对象字符串转换操作的运算逻辑

                .__len__()      len(obj)             定义对象长度操作的运算逻辑

 

                .__int__(self)      int(obj)             定义对象整数转换的运算逻辑

                .__float__(self)    float(obj)           定义对象浮点数转换的运算逻辑

                .__complex__(self)  complex(obj)         定义对象复数转换的运算逻辑

 

                .__round__(self)     round(obj)             定义对象四舍五入的运算逻辑

                .__bytes__(self)     bytes(obj)             定义对象字节串转换操作的运算逻辑

                .__bool__(self)      bool(obj)             定义对象布尔运算的运算逻辑

                .__format__(self)    obj.format()/format(obj)  定义对象格式化输出的运算逻辑

 

                例子:

                    class myList(list):  # 继承list 类

                        def __format__(self, format_spec):

                            "格式化输出,以逗号分隔"

                            t=[]

                            for c in self:

                                if type(c) == type("字符串"):

                                    t.append(c)

                                else :

                                    t.append(str(c))

                            return ", ".join(t)

 

                    ls = myList([6,1,2,3])

                    print(format(ls))

                    输出:

                        6, 1, 2, 3

                    注:

                        format([1,2,3,4])

                    输出:

                        [1, 2, 3, 4]

    unit2:Python类的多态:

        Python语言天生支持多态,这里没有特殊的语法需要我们记住,

        (1),多态的理解:

            多态 Polymorphism: 仅针对方法,方法灵活性的抽象

            >参数类型的多态: 一个方法能够处理多个类型的能力

            >参数形式的多态: 一个方法能够处理多个参数的能力

                >多态是OOP传统的一个概念,Python天然支持多态,不需要特殊的语法

 

            参数类型多态是指:方法不改变的情况下,可以支持多种参数类型

            参数形式多态是指:一个方法名字不改变的情况下,可以支持多个不同参数的输入

                目的还是为了提高代码复用的抽象级别。

技术图片

 

        (2),参数类型的多态:

            由于python的函数没有参数类型声明的限制,所以python天然支持参数类型的多态性,

           

            天然支持:Python方法的参数无类型声明的限制

            >Python的函数/方法的参数没有类型声明的限制,天然支持参数类型的多态性

            >Python编程的理念在于:文档约束,而非语法约束

            >对不同的参数类型的区分及功能,需要由程序员完成

 

            例子:

                class DemoClass:

                    def __init__(self,name):

                        self.name = name

 

                    def __id__(self):  #处理多态时,尤其是需要处理所有数据类型的时候,建议重载

                                        #一个Python内部的函数,这个内部函数要能跟所有类型打交道

                                        #举个例子id () 函数,任何一个类型都可以通过它获得内部id

                                        #我们可以重载它,使得返回一个我们需要的结果

                        return len(self.name)  #重载id ,使其返回用户的名字

 

                    def lucky(self,arg):

                        s =0

                        for c in self.name:

                            s += (ord(c)+id(arg)) %100

                        return s

                dc1 = DemoClass("Wang")

                dc2 = DemoClass("Li")

 

                print(dc1.lucky(10))

                print(dc1.lucky("10"))

                print(dc1.lucky(dc2))

 

                输出:

                    317

                    189

                    221

 

        (3),参数形式的多态:

            由于python的方法本身就是个函数,python的函数又支持可变参数,所以参数形式的多态也是

                天然的支持,

            >Python的函数/方法可以支持可变参数,支持参数形式的多态性

            >Python的类方法也是函数,函数的各种定义方式均有效

            >对不同参数个数及默认值的确定,需要由程序员完成

            例子:

            class DemoClass:

                def __init__(self,name):

                    self.name = name

 

                def __id__(self):

                    return len(self.name)

 

                def lucky(self,arg=0,more = 0):  #需要方法能够处理可变参数

                    s =0

                    for c in self.name:

                        s += (ord(c)+id(arg)+more) %100

                    return s

            dc1 = DemoClass("Wang")

 

            print(dc1.lucky())

            print(dc1.lucky(10))

            print(dc1.lucky(10,100))

            输出:

                237

                317

                317

 

    unit3:实例2:图像的四则运算

        需求分析:

            >加减法:两个图形相加减

            >乘除法:一个图像与一个数字之间的乘除法

技术图片

所要用到的两个库

技术图片

 

 

        具体代码:

            import numpy as np

            from PIL import Image

 

            class ImageObject:

                def __init__(self,path =""):

                    self.path = path

                    try:

                        self.data = np.array(Image.open(path))

                    except:

                        self.data = None

 

                def __add__(self, other):

                    image = ImageObject()

                    try :

                        image.data = np.mod(self.data+other.data,255)

                    except:

                        image.data = self.data

                    return image

                def __sub__(self, other):

                    image = ImageObject()

                    try :

                        imgae.data = np.mod(self.data - other.data,255)

                    except:

                        image.data  = self.data

                    return  image

                def __mul__(self, factor):

                    image = ImageObject()

                    try :

                        image.data = np.mod(self.data*factor,255)

                    except:

                        image.data = self.data

                    return image

 

                def __truediv__(self, factor):

                    image = ImageObject()

                    try :

                        image.data = np.mod(self.data/factor,255)

                    except:

                        image.data = self.data

                    return image

                def saveImage(self,path):

                    try :

                        im = Image.fromarray(self.data)

                        im.save(path)

                        return True

                    except:

                        return False

            a = ImageObject("d:/earth.jpg")

            b = ImageObject("d:/gray.jpg")

            (a+b).saveImage("d:/result_add.png")

            (a-b).saveImage("d:/result_sub.png")

            (a*2).saveImage("d:/result_mul.png")

            (a/2).saveImage("d:/result_div.png")

 

            注:

                a = 15

                print(a.__truediv__(2))

                print(a.__floordiv__(2))

            输出:

                7.5

                7

 

    unit4:Python对象的引用

        通过引用,将更加理解对象和类的概念

        (1),引用的理解:

            引用 Reference :对象的指针

            >引用是内存中真实对象的指针,表示为变量名或内存地址

            >每个对象至少存在一个引用(否则将会被垃圾回收机制回收) ,id() 函数用于获得引用

            >在传递参数和赋值时,Python传递对象的引用,而不是复制对象

 

            例子:

                ls = [1,2,3,4,5]

                lt = ls

                print(id(ls))

                print(id(lt))

            输出:

                2472917877896

                2472917877896

                这说明赋值的时候并没有真正的开辟内存,只是引用复制了一份

            Python内部对引用处理的机制:

                >对于不可变对象:immutable ,解释器会为相同值维护尽量少的内存区域

                >对于可变对象: mutable ,解释器为每个对象维护不同的内存区域

                例子:

                    a =10

                    b = a  #引用

                    c = 10

                    print(id(a))

                    print(id(b))

                    print(id(c))

                    输出:

                        1489175280

                        1489175280

                        1489175280

                        整数是不可变类型,10  都是在同一个内存

                再看个例子:              

                    a = "Python计算生态"

                    b = a  #引用

                    c = "Python"

                    d = "计算生态"

                    e = c+d

                    f = "Python计算生态"

                    print(id(a))

                    print(id(b))

                    print(id(c))

                    print(id(d))

                    print(id(e)) #对运算后的不会优化,会开辟新的内存

                    print(id(f))

                        输出:

                        2288379740048

                        2288379740048

                        2288377961192

                        2288379805520

                        2288379969680

                        2288379740048

                可变类型的引用:

                    la = []

                    lb = la  #引用

                    lc =[]

                    print(id(la))

                    print(id(lb))

                    print(id(lc))

 

                    输出:

                        1672822211656

                        1672822211656

                        1672824183816

                    再看:

                    la = []

                    lb = la

                    lb.append(1)

                    print(la,id(la))

                    print(lb,id(lb)) 

                    #这是因为lb 是引用,它和la 指向同一块内存

                    输出 :

                        [1] 1305658803272

                        [1] 1305658803272

           

            导致引用 +1 的情况:

                >对像被创建:d = DemoClass()

                >对象被引用:a = d

                >对象被作为函数或方法的参数: sys.getrefcount(d)

                    #这也是为何,使用sys.getrefcount()的时候,引用次数会加1 的原因了(因为对象做参数传递了)

                >对象被作为一个容器中的元素:ls =[d]

           

            导致引用 -1 的情况:

                >对像被删除:del d

                >对象的名字被赋予新的对象:d = 123

                >对象离开作用域:func() 函数的局部变量count

                >对象所在容器被删除:del ls

                注:如果一个对象的引用为0,那么它就会被垃圾回收机制清理掉,内存就会被释放

           

            引用的理解:

                >引用是内存中真实对象的指针,表示为变量名或内存地址

                >在传递参数和赋值时,Python传递对象的引用,而不是复制对象

                >不可变对象和可变对象的内存管理略有不同

                    对于可变对象,每次都会真实的创建对象,

                    对不可变对象,它会尽可能的复用不可变对象的内存空间

        (2),浅拷贝和深拷贝:

            >拷贝:赋值一个对象为新的对象,内存空间有"变化"

            >浅拷贝: 仅复制最顶层对象的拷贝方式 ,默认拷贝方式

            >深拷贝: 迭代复制所有对象的拷贝方式

 

            1,浅拷贝:

            例子:

                ls = ["Python",[1,2,3]]

                la = ls.copy() #引用

                lb = ls[:]#引用

                lc = list(ls)#引用

 

                print("ls:",id(ls),ls)

                print("la:",id(la),la)

                print("lb:",id(lb),lb)

                print("lc:",id(lc),lc)

            输出:

                ls: 1317721824264 [‘Python‘, [1, 2, 3]]

                la: 1317721824008 [‘Python‘, [1, 2, 3]]

                lb: 1317721824072 [‘Python‘, [1, 2, 3]]

                lc: 1317721844040 [‘Python‘, [1, 2, 3]]

 

                这时候其实只是列表被拷贝了,但元素没有被拷贝,

技术图片

 

                看如下:

                    ls = ["Python",[1,2,3]]

                    la = ls.copy() #引用

                    lb = ls[:]#引用

                    lc = list(ls)#引用

 

                    for i in [ls,la,lb,lc]:

                        for c in i:

                            print(c,id(c)," ",end =" ")

                        print(" ",i,id(i))

                    输出: 

                        Python 2547295034088   [1, 2, 3] 2547295011976     [‘Python‘, [1, 2, 3]] 2547301178376

                        Python 2547295034088   [1, 2, 3] 2547295011976     [‘Python‘, [1, 2, 3]] 2547301178120

                        Python 2547295034088   [1, 2, 3] 2547295011976     [‘Python‘, [1, 2, 3]] 2547301178184

                        Python 2547295034088   [1, 2, 3] 2547295011976     [‘Python‘, [1, 2, 3]] 2547301198152

                    注:实际上复制的是列表中的指针。

                    这带来的问题:

                        ls = ["Python",[1,2,3]]

                        la = ls.copy() #引用

                        lb = ls[:]#引用

                        lc = list(ls)#引用

 

                        lc[-1].append(4)

                        print(lc,la)

                        print(ls,lb)

                        输出:

                            [‘Python‘, [1, 2, 3, 4]] [‘Python‘, [1, 2, 3, 4]]

                            [‘Python‘, [1, 2, 3, 4]] [‘Python‘, [1, 2, 3, 4]]

                        我们发现只要修改一个,其他都发生变化了,

            2,深拷贝:

                完全拷贝对象的内容

                >这个要采用copy标准库的deepcopy() 方法

                >迭代拷贝对象内各层次对象,完全新开辟内存建立对象

                >深拷贝仅针对可变类型,不可变类型无需创建新对象

                    import copy

 

                    ls = ["python",[1,2,3]]

                    lt = copy.deepcopy(ls)

                    for i in [ls,lt]:

                        for c in i :

                            print(c,id(c)," ",end = " ")

                        print(" ",i,id(i))

                    输出:

                        python 2149527044816   [1, 2, 3] 2149529151752     [‘python‘, [1, 2, 3]] 2149529115400

                        python 2149527044816   [1, 2, 3] 2149529151688     [‘python‘, [1, 2, 3]] 2149529115464

                        注:不可变类型Python 是没有新创建的,

                            可变类型[1,2,3] 深拷贝是要新创建的

            小结:对象的拷贝:

                浅拷贝和深拷贝:

                    >浅拷贝:仅复制最顶层对象的拷贝方式,默认拷贝方式

                    >深拷贝:迭代复制所有对象的拷贝方式,采用copy库的deepcopy()

                    >一般深拷贝都与可变类型关联

                            

 

        (3),类的方法应用:

            再看类的实例方法:

                >定义方式:def  <实例方法名>(self,<参数列表>)

                >实例方法名(函数名)也是一种引用,即对方法本身的引用

                >当方法被引用时,方法(函数)将产生一个对象:方法对象

                class DemoClass:

                    def __init__(self,name):

                        self.name = name

 

                    def lucky(self,arg= 0):

                        s = 0

                        for c in self.name:

                            s += (ord(c)+id(arg))%100

                        return s

                dc1 = DemoClass("Li")

                lucky = dc1.lucky

                print(DemoClass.lucky(dc1,10))

                print(dc1.lucky(10))

                print(lucky(10))

          

                <对象名>.<方法>(方法参数)   等价于    <类名>.<方法名>(<对象名>,方法参数)

 

                输出:

                    141

                    141

                    141

               

    unit5:Python类的高级话题:

        (1),命名空间的理解:

            命名空间 Namespace :从名字到对象的一种映射

            >作用域:全局变量名在模块命名空间,局部变量在函数命名空间

            >属性和方法在类命名空间,名字全称: <命名空间>.<变量/函数名>

            >命名空间底层由一个dict 实现,变量名是键,变量引用的对象是值

 

            例子:

            >复数 z ,z.real 和 z.imag 是对象z命名空间的两个属性

            >对象d,d.name 和d.printName() 是对象d命名空间的属性和方法

           

            >global 和 nonlocal 是两个声明命名空间的保留字

           

            例子: 

                count = 0 #模块的命名空间

 

                def getCounting(a):

                    count = 0   #第一层函数的命名空间

                    if a != "":

                        def doCounting():

                            nonlocal count   #第二层函数的命名空间

                            count += 1

                        doCounting()

                    return count

                print(getCounting("1"),count)

                print(getCounting("2"),count)

                print(getCounting("3"),count)

            输出:

                1 0

                1 0

                1 0

                注:nonlocal的作用,是不在当前,向上逐层去找(到全局为止,不找全局)

            例子:

                count = 0 #模块的命名空间

 

                def getCounting(a):

                    #count = 0   #第一层函数的命名空间

                    if a != "":

                        def doCounting():

                            nonlocal count   #第二层函数的命名空间

                            count += 1

                        doCounting()

                    return count

                print(getCounting("1"),count)

                print(getCounting("2"),count)

                print(getCounting("3"),count)

            输出:

                File "C:/Users/Administrator/Desktop/test/test.py", line 7

                    nonlocal count   #第二层函数的命名空间

                SyntaxError: no binding for nonlocal ‘count‘ found

           

            如果想用全局中的就要用global来声明了:

                例子:

                    count = 0 #模块的命名空间

 

                    def getCounting(a):

                        #count = 0   #第一层函数的命名空间

                        if a != "":

                            def doCounting():

                                global count   #第二层函数的命名空间

                                count += 1

                            doCounting()

                        return count

                    print(getCounting("1"),count)

                    print(getCounting("2"),count)

                    print(getCounting("3"),count)

                    输出:

                        1 1

                        2 2

                        3 3

 

 

 

        (2),类的特殊装饰器:

            我们先看一个问题:

                d = DemoClass("LI")

                d.age = -99

                >d.age如果作为年龄,其值有误,但属性不能检测异常值

                >如何为属性增加异常检测呢?

            这就要用Python的特性装饰器了,

            @property :类的特性装饰器

            >使用@property 把类中的方法变成对外可见的“属性”,不是真正的属性,还是方法

            >类内部:表现为方法

            >类外部:表现为属性

                例子:

                    class DemoClass:

                        def __init__(self,name):

                            self.name = name

 

                        @property   #@property 用于转换方法为属性

                        def age(self):

                            return self._age

 

                        @age.setter  # @<方法名>.setter  用于设定属性的赋值操作

                        def age(self,value):

                            if value < 0 or value>100:

                                value =30

                            self._age = value   #将value 给self._age

 

                    dc1 = DemoClass("Li")

                    dc1.age = -100

                    print(dc1.age)  #dc1.age其实调的是dc1.age() 

                输出:30

                    dc1.age 是被特性装饰器装饰过的,

 

                总结,要想检测一个属性,可以@property 给它装饰,并用@<方法名>.setter 获取外部的值

 

        (3),自定义的异常类型:

            异常Exception 也是一种Python类:

                >try -except 捕捉自定义的异常

                >继承Exception类,可以给出自定义的异常类

                >自定义异常类时类继承的是Exception,那么,它就可以被try -except 捕获

                例子:

                    class DemoException(Exception):

                        pass

                    try:

                        raise DemoException()  #使用raise 抛出自定义的异常

                    except:

                        print("捕获DemoException异常")

                    输出:

                        捕获DemoException异常

                   

                另一例子:

                    class DemoException(Exception):

                        def __init__(self,name,msg = "自定义异常"):

                            self.name = name

                            self.msg = msg

                    try:

                        raise DemoException("脚本错误")

                    except DemoException as e: # 捕捉这个异常及异常对象

                        print(" 异常的报警是 ".format(e.name,e.msg))

                    输出:

                        脚本错误 异常的报警是 自定义异常

        (4),类的名称修饰:

            名称修饰 Name Mangling :类中名称的变化约定

            >Python通过名称修饰完成一些重要功能

            >采用下划线进行名称修饰,分5中情况

            >_X  ,X_ ,__X ,__X__ ,_

           

            先看: _X

                >单下划线开头属性或方法为类内部使用 (PEP8 规定)

                >只是约定,仍然可以通过<对象名>.<属性名> 方式访问

                >功能:from XX import * 时不会导入单下下划线开头的属性或方法

                例子:

                    class DemoClass(Exception):

                        def __init__(self,name):

                            self.name = name

                            self._nick =name +"同志"  #约定_nick 只在内部使用

                        def getNick(self):

                            return self._nick

 

                    dc1 = DemoClass("LI")

                    print(dc1.getNick())

                    print(dc1._nick)  # 仍然可以外部调用

                输出:

                    LI同志

                    LI同志

            第二: X_ 

                单下划线接我的名称修饰

                >单下划线结尾属性或方法为避免与保留字或已有命名冲突 (PEP 8)

                >只是约定,无任何功能性对应

                例子: 

                    class DemoClass(Exception):

                        def __init__(self,name):

                            self.name = name

                            self.class_ =name +"同志"

                        def getNick(self):

                            return self.class_  # 仅是为了避免重名

 

                    dc1 = DemoClass("LI")

                    print(dc1.getNick())

                    print(dc1.class_) 

            第三:__X 

                双下划线开头的名称修饰

                >双下划线开头属性或方法将被解释器修改名称,避免命名冲突

                >不是约定,而是功能性,python 解释器会修改它,实现私有属性,私有方法

                >__X 会被修改为 : _<类名>__X 

                例子:

                    class DemoClass(Exception):

                        def __init__(self,name):

                            self.name = name

                            self.__nick =name +"同志"

                        def getNick(self):

                            return self.__nick

 

                    dc1 = DemoClass("LI")

                    print(dc1.getNick())

                    print(dc1._DemoClass__nick)

                    print(dc1.__nick)  # 将报错

            第四: __X__

                双下划綫开头和结尾的名称修饰

                >双下划线开头和结尾的属性或方法无任何特殊功能,名字不被修改

                >部分名称是保留属性/保留方法

 

                例子:

                    class DemoClass(Exception):

                        def __init__(self,name):

                            self.name = name

                            self.__nick__ =name +"同志"

                        def getNick(self):

                            return self.__nick__

 

                    dc1 = DemoClass("LI")

                    print(dc1.getNick())

                    print(dc1.__nick__) 

                    #不报错

            第五: _

                >单下划线是一个无关紧要的名字,无特殊功能

                for _ in range(10):

                    print("hello world")       

 

            小结:类的名称修饰:

                >_X :约定内部使用,仅在import *时不被引用

                >X_ :避免与保留字冲突,无特殊功能

                >__X :不被子类继承,可用于设定私有,改变为:_<类名>__X

                >__X__ :无特殊功能,部分用于保留属性和保留方法

                >_ : 无特殊功能,不重要的命名

        (5),Python最小空类:

            class <类名>():

                pass

           

            >类是一个命名空间,最小空类可以当做命名空间来使用

            >最小空类可辅助数据存储和使用

                动态增加属性是Python类的一个特点

            例子:

                class EmptyClass:

                    pass

 

                a = EmptyClass()

 

                a.name = "Li"

                a.age = 50

                a.family = "son":"xiao Li"

                print(a.family)

                print(a.__dict__)

            输出:

                ‘son‘: ‘xiao Li‘

                ‘name‘: ‘Li‘, ‘family‘: ‘son‘: ‘xiao Li‘, ‘age‘: 50

 

            作用:用最小空类来组织数据

 

以上是关于Python面向对象语法精讲的主要内容,如果未能解决你的问题,请参考以下文章

PHP面试题精讲 — 面向对象类

python语法基础-面向对象-长期维护

Python面向对象:面向对象(OOP)基本概念类和对象基础语法封装案例私有属性和私有方法

Python面向对象:面向对象(OOP)基本概念类和对象基础语法封装案例私有属性和私有方法

Python基础语法介绍:面向对象编程

python语法基础-面向对象-进阶-长期维护