• 面向对象


      类,就是一种事物,具有共性。比如dict,人,熊猫

      对象,类的实例化后所产生的,具有个性,比如{1:‘vf’},春哥,团团。

    申明类:

    class 类名:
        '类的文档字符串'#类的静态属性
      def __init__(self,参数)
        实例化所需要的参数代码
      def 功能

    面向对象小结——定义及调用的固定模式

    class 类名:
        def __init__(self,参数1,参数2):
            self.对象的属性1 = 参数1
            self.对象的属性2 = 参数2
    
        def 方法名(self):pass
    
        def 方法名2(self):pass
    
    对象名 = 类名(1,2)  #对象就是实例,代表一个具体的东西
                      #类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
                      #括号里传参数,参数不需要传self,其他与init中的形参一一对应
                      #结果返回一个对象
    对象名.对象的属性1   #查看对象的属性,直接用 对象名.属性名 即可
    对象名.方法名()     #调用类中的方法,直接用 对象名.方法名() 即可
    面向对象小结——定义及调用的固定模式

     我们定义的类的属性到底存到哪里了?有两种方式查看

    dir(类名):查出的是一个名字列表

    类名.__dict__:查出的是一个字典,key为属性名,value为属性值

     特殊的类属性

    类名.__name__# 类的名字(字符串)

    类名.__doc__# 类的文档字符串

    类名.__base__# 类的第一个父类(在讲继承时会讲)

    类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)

    类名.__dict__# 类的字典属性

    类名.__module__# 类定义所在的模块

    类名.__class__# 实例对应的类(仅新式类中)

    class Person:
        country = 'China'
        def __init__(self,name,sex,age,hobby):
            self.name=name
            self.sex=sex
            self.age=age
            self.hobby=hobby
        def func(self):
            print(dir(self))
    p1=Person('alex','male',68,'study')
    print(dir(Person))
    print(dir(p1))
    print(p1.__dict__)
    print(Person.__name__)
    print(Person.__doc__)
    print(Person.__base__)
    print(Person.__bases__)
    print(Person.__module__)
    print(Person.__class__)
    print(Person.__dict__)
    #输出的结果为
    '''

    ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'country', 'func'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'country', 'func', 'hobby', 'name', 'sex'] {'hobby': 'study', 'sex': 'male', 'name': 'alex', 'age': 68} Person None <class 'object'> (<class 'object'>,) __main__ <class 'type'> {'__init__': <function Person.__init__ at 0x0000000000832620>, 'country': 'China', '__doc__': None, '__dict__': <attribute '__dict__' of 'Person' objects>, '__module__': '__main__', 'func': <function Person.func at 0x00000000008326A8>, '__weakref__': <attribute '__weakref__' of 'Person' objects>} '''

     面向对象的组合

      组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

     

     面向对象的命名空间

    class name_space:
        code='utf-8'
        def __init__(self,name,sex,age):
            self.name=name
            self.age=age
            self.sex=sex
    lhy=name_space('lhy','female',18)
    dxx=name_space('dxx','male',23)
    print(name_space.code)#utf-8
    print(lhy.code)#utf-8
    print(lhy.age)#18
    #print(name_space.name)#报错
    #name_space.__dict__['code']='unicode'#报错
    name_space.code='unicode'
    print(name_space.code)#unicode
    print(lhy.code)#unicode
    lhy.__dict__['code']='gbk'
    print(lhy.__dict__)#gbk
    print(lhy.code)#gbk
    print(name_space.code)#unicode
    lhy.__dict__.pop('code')#删除code
    print(lhy.code)#unicode
     
    类的静态变量是可以通过 类.属性名来改变的,但是不可以通过类.__dict__来进行改变。同时静态属性的改变影响对象的静态属性,应为这个属性是绑定在类中并指向一个内存地址的
    对象,可也以改变静态属性的。对象名.属性来改变,但是不会影响其他对象以及类的这静态属性的,相当于自己在自己的命名空间开了一新的的空间,不再是绑定关系,删除之后,才会恢复绑定关系

    再看代码

    class group:
         hobby=['eat','drink','swim']
    wjw=group
    jjs=group
    print(group.hobby)#print(group.hobby)
    print(wjw.hobby)#print(group.hobby)
    print(jjs.hobby)#print(group.hobby)
    wjw.hobby.pop()
    print(group.hobby)#['eat', 'drink']
    print(wjw.hobby)#['eat', 'drink']
    print(jjs.hobby)#['eat', 'drink']

    类里的名字有 类变量(静态属性量)+ 方法名(动态属性)
    对象里的名字 对象属性
    对象 —— > 类
    对象找名字 : 先找自己的 找类的 再找不到就报错
    对象修改静态属性的值
    对于不可变数据类型来说,类变量最好用类名操作
    对于可变数据类型来说,对象名的修改是共享的,重新赋值是独立的

    面向对象的三大特征:继承,多态,封装

    继承

    单继承

    父类又称超类,基类
    子类又称派生类

    class A:
        def fun(self):
            print('A')
            pass
    class B:
        def fun(self):
            print('B')
            pass
    
    class A_son(A):
        def fun(self):
            print('A_son(A)')
            pass
    
    class AB_son(A,B):
        def fun(self):
            print('AB_son(A,B)')
            pass
    print(A_son.__bases__)#(<class '__main__.A'>,) 表示A的子类
    print(AB_son.__bases__)#(<class '__main__.A'>, <class '__main__.B'>)表示A和B的子类

    提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

    继承与抽象:向抽象在继承。

    请看代码

    class People:
        def eat(self):
            print('%s eat a bread'%self.name)
        def sleep(self):
            print('%s is slepping'%self.name)
        def look_for_sex(self):
                print('%s is %s' % (self.name, self.sex))
    class Xiaoming(People):
        def __init__(self,name,sex):
            self.name=name
            self.sex=sex
    class Xiaohong(People):
        def __init__(self,name,sex):
            self.name=name
            self.sex=sex
    xiaoming=Xiaoming('xiaoming','male')
    xiaohong=Xiaohong('xiaohong','female')
    xiaoming.eat()#xiaoming eat a bread
    xiaohong.look_for_sex()#xiaohong is female

    注意:此时的父类定义时没有传参数,故可以直接调用

    派生

    子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类)。

    需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。

    class A:
        def func(self):
            print('it is father function')
    class B(A):
        def func(self):
            print('it is son function')
    b= B()
    b.func()#it is son function
    father_and_son_function

    父类中没有的属性 在子类中出现 叫做派生属性
    父类中没有的方法 在子类中出现 叫做派生方法
    只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
    如果父类 子类都有 用子类的

      如果还想用父类的,单独调用父类的:

      父类名.方法名 需要自己传self参数

      super().方法名 不需要自己传self

      在外部调用父类方法是super().方法名 需要自己在()中填写(子类名,对象名)

                      内部调用(子类名,self)

      注意区分内外掉用区别

      super().hahaha() 等价super(B,self).hahaha(),一般用前面的

    正常的代码中 单继承 === 减少了代码的重复
    继承表达的是一种 子类是父类的关系

    关于继承传参数

    class A:
        def __init__(self,name,sex,age):
            self.name=name
            self.age= age
            self.sex=sex
            print('A传参数完成')
    class B(A):
        def __init__(self,name,age,sex,hobby):
            super().__init__(name,age,sex)
            # super(B, self).__init__(name, age, sex)
            #也可以这么写,这样就能统一self
            self.hobby=hobby
            print('hobby传参完成')
    a =B('alex',16,'male','study')
    #结果
    #A传参数完成
    #hobby传参完成
    继承传参

    多继承:

    多继承中,我们子类的对象调用一个方法,默认是就近原则,找的顺序是什么?
    经典类中 深度优先
    新式类中 广度优先
    python2.7 新式类和经典类共存,新式类要继承object
    python3 只有新式类,默认继承object
    经典类和新式类还有一个区别 mro方法只在新式类中存在

       类名.mro()  查找多继承的顺序

    super 只在python3中存在
    super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的

    砖石继承

     

    抽象类与接口类

    接口类 : python原生不支持
    抽象类 : python原生支持

    规范 :接口类或者抽象类都可以
    接口类 支持多继承,接口类中的所有的方法都必须不能实现 —— java
    抽象类 不支持多继承,抽象类中方法可以有一些代码的实现 —— java

    接口类

    from abc import ABCMeta,abstractmethod
    class start_game(metaclass=ABCMeta):
        @abstractmethod
        def start(self,num):pass
    class LOL(start_game):
        def start(self,num):
            print('%s second will be open Lol'%num)
    class DNF(start_game):
        def start(self,num):
            print('%s second will be open DNF' % num)
    class QQ(start_game):
        def begin(self,num):
            print('%s second will be open QQ' % num)
    lol=LOL()
    lol.start(5)#5 second will be open Lol
    dnf=DNF()
    dnf.start(6)#6 second will be open DNF
    qq = QQ()
    qq.begin(5)#TypeError: Can't instantiate abstract class QQ with abstract methods start

     解析

     接口内的多继承

    from abc import abstractmethod,ABCMeta
    class Swim_Animal(metaclass=ABCMeta):
        @abstractmethod
        def swim(self):pass
    
    class Walk_Animal(metaclass=ABCMeta):
        @abstractmethod
        def walk(self):pass
    
    class Fly_Animal(metaclass=ABCMeta):
        @abstractmethod
        def fly(self):pass
    
    class Tiger(Walk_Animal,Swim_Animal):
        def walk(self):
            pass
        def swim(self):
            pass
    class OldYing(Fly_Animal,Walk_Animal):pass
    class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass

    抽象类

     与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

    为什么要有抽象类

        如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类是从一堆中抽取相同的内容而来的,内容包括数据属性和函数属性。

      比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

        从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

      从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

    import abc #利用abc模块实现抽象类
    class All_file(metaclass=abc.ABCMeta):
        all_type='file'
        @abc.abstractmethod #定义抽象方法,无需实现功能
        def read(self):
            '子类必须定义读功能'
            with open('filaname') as f:
                pass
        @abc.abstractmethod #定义抽象方法,无需实现功能
        def write(self):
            '子类必须定义写功能'
            pass
    class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('文本数据的读取方法')
        def write(self):
            print('文本数据的读取方法')
    class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('硬盘数据的读取方法')
        def write(self):
            print('硬盘数据的读取方法')
    class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
        def read(self):
            print('进程数据的读取方法')
        def write(self):
            print('进程数据的读取方法')
    wenbenwenjian=Txt()
    yingpanwenjian=Sata()
    jinchengwenjian=Process()
    #这样大家都是被归一化了,也就是一切皆文件的思想
    wenbenwenjian.read()
    yingpanwenjian.write()
    jinchengwenjian.read()
    print(wenbenwenjian.all_type)
    print(yingpanwenjian.all_type)
    print(jinchengwenjian.all_type)
    #输出结果

    #文本数据的读取方法
    #硬盘数据的读取方法
    #进程数据的读取方法
    #file
    #file
    #file

    抽象类 : 规范
    一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现
    多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中


    抽象类还是接口类 : 面向对象的开发规范 所有的接口类和抽象类都不能实例化
    java :
    java里的所有类的继承都是单继承,所以抽象类完美的解决了单继承需求中的规范问题
    但对于多继承的需求,由于java本身语法的不支持,所以创建了接口Interface这个概念来解决多继承的规范问题

    python
    python中没有接口类 :
    python中自带多继承 所以我们直接用class来实现了接口类
    python中支持抽象类 : 一般情况下 单继承 不能实例化
    且可以实现python代码

    多态

    python 天生支持多态属于动态强类型语言

    鸭子类型
    list tuple
    不崇尚根据继承所得来的相似
    我只是自己实现我自己的代码就可以了。
    如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
    list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的
    优点 : 松耦合 每个相似的类之间都没有影响
    缺点 : 太随意了,只能靠自觉

    强类型语言 多态
    python 语言 鸭子类型

     封装

    广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种
    只让自己的对象能调用自己类中的方法

    狭义上的封装 —— 面向对象的三大特性之一
    属性 和 方法都藏起来 不让你看见

    #其实这仅仅这是一种变形操作
    #类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
    
    class A:
        __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
        def __init__(self):
            self.__X=10 #变形为self._A__X
        def __foo(self): #变形为_A__foo
            print('from A')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.
    
    #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

    解析

    class conformation:
        def __init__(self,name,sex,age):
            self.__name=name
            self.sex=sex
            self.__age=age
        def __func(self):
            return self.__age+7
        def function(self):
            print(self.__func())
    xiaoming = conformation('xiaoming','male',19)
    print(xiaoming.sex)
    # print(xiaoming.name)#报错
    print(xiaoming._conformation__name)
    print(xiaoming.__dict__)
    #{'sex': 'male', '_age': 19, '_conformation__name': 'xiaoming'}
    print(xiaoming._conformation__func())
    xiaoming.function()
    '''输出结果
    male
    xiaoming
    {'_conformation__name': 'xiaoming', 'sex': 'male', '_conformation__age': 19}
    26
    26
    '''
    代码

    这种自动变形的特点:

    1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

    2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

    3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

    这种变形需要注意的问题是:

    1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

    2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形

    在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

    #正常情况
    >>> class A:
    ...     def fa(self):
    ...         print('from A')
    ...     def test(self):
    ...         self.fa()
    ... 
    >>> class B(A):
    ...     def fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from B
     
    
    #把fa定义成私有的,即__fa
    >>> class A:
    ...     def __fa(self): #在定义时就变形为_A__fa
    ...         print('from A')
    ...     def test(self):
    ...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
    ... 
    >>> class B(A):
    ...     def __fa(self):
    ...         print('from B')
    ... 
    >>> b=B()
    >>> b.test()
    from A
    View Code

    会用到私有的这个概念de场景
    1.隐藏起一个属性 不想让类的外部调用
    2.我想保护这个属性,不想让属性随意被改变
    3.我想保护这个属性,不被子类继承

  • 相关阅读:
    开源项目中标准文件命名和实践
    linux远程拷贝命令-scp
    Linux访问Windows共享目录的方法——smbclient
    ADB Fix error : insufficient permissions for device
    APT典型应用示例
    我的参考书籍列表
    GCC Reference
    GNU make简介
    Windows下搭建Android NDK开发环境及命令行编译
    Git命令行基本操作
  • 原文地址:https://www.cnblogs.com/accolade/p/10500039.html
Copyright © 2020-2023  润新知