• 面向对象一


    一.面向对象初始

    函数式编程相较于面向过程编程的优点

    1.减少代码的重用性。
    2.增强代码的可读性。
    

    面向对象编程相较于函数编程的优点

    1.是一类相似功能函数的集合,使代码更清晰化,更合理化。
    

    概念

    类的实例化:类名+()的过程称为类的实例化,产生一个对象(实例).
    实例化做三件事:
        1.执行object的__new__()方法,产生并返回一个空对象(在内存中开辟了一个对象空间)
        2.自动触发类的内部__init__函数的执行,将空对象作为参数传给__init__函数
        3.在__init__方法中通过self给对象空间添加属性
    查看对象的名称空间(只存对象独有的):
        print(obj.__dict__)
    对象属性的查找顺序(对象的命名空间->类的命名空间):
        1.类的数据属性(给对象用,不同对象对应的地址相同)
        2.类的函数属性(给对象用,不同对象)
        #1.对象名.__dict__
        #2.类名.__dict__
    

    类的结构

    类的结构从大方向来说就分为两部分:

    1.静态变量 2.动态方法

    class Human:
        '''静态变量'''
        mind = "有思想"
        feeling = "有感情"
        
        '''动态方法'''
        def work(self):
            print("会工作")
    

    二.从类名的角度研究类

    img

    类名操作静态属性

    1.查看类中所有内容,__dic__方式

    class Human:
        mind = "有思想"
        feeling = "有感情"
        
        def work(self):
            print("会工作")
            
    print(Human.__dic__)
    Human.__dic__['mind'] = "没有思想"  # 错误,通过__dic__只能查询,不能修改
    

    2.万能的.

    class Human:
        mind = "有思想"
        feeling = "有感情"
        
        def work(self):
            print("会工作")
    # 查 print(Human.mind)
    # 改 Human.mind = "五思想"
    # 增 Human.hobby = "玩"
    # 删 del Human.hobby 
    

    类名操作动态方法

    除了两个特殊方法(静态方法,类方法),一般不会通过类名操作类中方法

    class Human:
        mind = "有思想"
        feeling = "有感情"
        
        def work(self):
            print("会工作")
    Human.work(1)  # 需要传参
    

    三.从对象角度研究类

    img

    对象操作对象空间属性

    1.对象查询对象中的所有属性

    class Human:
        mind = "有思想"
        feeling = "有感情"
        
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
        def work(self):
            print("会工作")
    obj = Human("张三",18)
    print(obj.__dict__) # {"name":"张三","age":18}
    

    2.对象操作对象中的单个属性,万能的.

    class Human:
        mind = "有思想"
        feeling = "有感情"
        
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
        def work(self):
            print("会工作")
    obj = Human("张三",18)
    # 增 obj.sex = "男"   此举是将sex属性添加到__init__()方法中
    # 删 del obj.sex 
    # 改 obj.name = "小明"
    # 查 print(obj.__dict__)
    

    对象查看类中的属性

    class Human:
        mind = "有思想"
        feeling = "有感情"
        
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
        def work(self):
            print("会工作")
            
    obj = Human("张三",19)
    print(obj.mind)  # 先从对象空间找,找不到去类中找
    

    对象操作类中的方法

    class Human:
        mind = "有思想"
        feeling = "有感情"
        
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
        def work(self):
            print("会工作")
            
    obj = Human("张三",20)
    obj.work()
    

    类中的方法一般都是通过对象执行(除去类方法、静态方法是类本身调用的)的。

    四.类与类之间的联系

    1.依赖关系

    将一个类的类名或者对象传入另一个类的方法

    class Elephant:
        def __init__(self,name):
            self.name = name
        def open(self,obj):
            print(f'{self.name}默念三生')
            obj.be_open()
    
    class Refrigerator:
        def __init__(self,name):
            self.name = name
        def be_open(self):
            print(f'{self.name}冰箱被打开了')
            
    qiqi = Elephant("琪琪")
    haier = Refrigerator("海尔")
    qiqi.open(haier)
    

    2.组合关系

    给一个类的对象封装一个属性,此属性为另一个类的对象

    class Boy:
        def __init__(self,name,girlfriend=None):
            self.name = name
            self.girlfriend = girlfriend
            
        def have_a_dinner(self):
            print(f'{self.name}请他的{self.girlfriend.age}岁的女朋友{self.girlfriend.name}吃饭!')
    
    class GirlFriend:
        def __init__(self,name,age):
            self.name = name
            self.age = age
            
    boy = Boy("小明")
    girl = GirlFriend("如花",30)
    boy.girlfriend = girl
    boy.have_a_dinner()
    

    五.单继承

    继承是一种新建类的方式,新建的类称为子类派生类,父类也称为基类超类

    1.继承的优点

    1.增加了类的耦合性
    2.减少了重复代码
    3.使代码更加规范化,合理化
    

    2.类名+方法调用父类中方法

    严格来说,此方法与继承无关

    class Father:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    class Son(Father):
        def __init__(self,name,age):
            Father.__init__(self,name,age)
    
    son = Son("小明",20)
    print(son.__dict__)
    

    3.super()方法

    super()的返回值是一个特殊的对象,专门用来调用父类中的属性

    class Animal:
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def eat(self):
            print("动物可以吃饭!")
            print(f"{self.name},{self.age},{self.sex}")
    
    class Person(Animal):
        def __init__(self,name,age,sex):
            # super().__init__(name,age,sex)
            super(Person,self).__init__(name,age,sex)
    
        def eat(self):
            print("人可以吃饭!")
            super().eat()
    
    person = Person("小明",19,"男")
    person.eat()
    

    六.多继承

    1.继承的分类

    只有在python2中才区分新式类和经典类。python3中,所有类都是新式类。

    新式类

    继承object的类,以及该类的子类,都是新式类

    在python3中,如果一个类没有指定继承的父类,默认就继承object

    经典类

    没有继承object的类,以及该类的子类,都是经典类

    2.查找顺序

    2.1经典类的深度优先

    2.2新式类的mro(c3)算法(参考文献:https://www.cnblogs.com/jin-xin/articles/10274734.html)

    七.封装

    1.什么是封装

    封装就是将属性私有化,提供共有的方法访问私有属性

    2.为什么要用封装?

    通过封装,可以实现对属性数据的访问限制,同时增加了程序的可维护性

    3.图解

    将"小明"和18封装给foo对象
    img

    八.多态

    1.多态定义

    同一个对象,多种形态。python默认支持多态。

    在python中,定义变量a,a=10,a="hello",a=[1,2,3],就是默认支持多态的体现。在一个类中,实例化出来多个对象,每个对象都有独一的形态,这也是多态的体现。

    2.鸭子类型

    两个完全没有耦合性的类中有相同功能的方法,我们为这两个方法设定相同的名字,那么这两个方法就互成为鸭子类型。

    class A:
        def f1(self):
            print("in A f1")
        def f2(self):
            print("in A f2")
    class B:
        def f1(self):
            print("in B f1")
        def f2(self):
            print("in B f2")
    
    # 如上:A和B类中的f1、f2方法互为鸭子类型
    # 这样的例子很多:str、tuple、list都有index方法,就是互为鸭子类型
    

    九.类的强制约束

    1.提取父类

    python语言惯用的一种约束方式,在父类中主动抛出错误

    class Payment:
        def pay(self,money):
            raise Exception("你没有实现pay方法")   #尽量抛出的是NotImplementError
    
    class QQpay(Payment):
        def pay(self,money):
            print(f"使用QQ支付了{money}")
    
    class Alipay(Payment):
        def pay(self,money):
            print(f"使用Ali支付了{money}")
    
    class Wechat(Payment):
        def fuqian(self,money):
            print(f"使用Wechat支付了{money}")
    
    def pays(obj,money):   # 新建的统一支付接口
        obj.pay(money)
    
    qqpay = QQpay()
    alipay = Alipay()
    wechat = Wechat()
    pays(qqpay,100)
    pays(alipay,200)
    pays(wechat,300)    # 子类中没有此方法,会执行父类的,父类抛出错误
    

    2.使用抽象类

    借鉴于java语言,定义抽象类的概念,做到真正的强制约束。

    '''
    抽象类和接口类做的事情 :建立规范
    制定一个类的metaclass是ABCMeta,
    那么这个类就变成了一个抽象类(接口类)
    这个类的主要功能就是建立一个规范
    
    '''
    
    from abc import ABCMeta,abstractmethod
    class Payment(metaclass=ABCMeta):
        @abstractmethod
        def pay(self,money):
            pass
    
    class QQpay(Payment):
        def pay(self,money):
            print(f"使用QQ支付了{money}")
    
    class Alipay(Payment):
        def pay(self,money):
            print(f"使用Ali支付了{money}")
    
    class Wechat(Payment):
        def fuqian(self,money):
            print(f"使用Wechat支付了{money}")
    
    def pays(obj,money):   # 新建的统一支付接口
        obj.pay(money)
    
    qqpay = QQpay()
    alipay = Alipay()
    wechat = Wechat()
    pays(qqpay,100)       
    pays(alipay,200)
    pays(wechat,300)        #初始化对象就会报错
    

    十.super()深入了解

    https://www.cnblogs.com/jin-xin/articles/10279154.html
    按照self对象从属于类的mro的顺序,执行Foo类的下一个类

    class F:
        def f1(self):
            pass
    class Foo(F):
        def f1(self):
            super(Foo,self).f1()
    foo = Foo()
    foo.f1()
    
    
    
    #############
    class A:
    
       def __init__(self):
           self.__func()                        # self._A__func()
    
        def __func(self):                     # _A__func()
            print('in A __func')
    
    class B(A):
       def __func(self):                     # _B__func()
           print('in B __func')
    
    
    obj = B()         #执行结果:in A_func
    

    十一.类的组成成员

    类大致分为两块区域
    img

    细分

    class A:
        name = 'alex'                  #静态字段
        __iphone = '1259874159'        #私有静态字段
        
        def __init__(self,name,age):   #特殊方法
            self.name = name           #对象普通属性
            self.__age = age           #对象私有属性
        def func1(self):               #普通方法
            pass
        def __func(self):              #私有方法
            pass
        
        @classmethod                   #类方法
        def class_func(cls):
            pass
        
        @staticmethod                  #静态方法
        def static_func():
            pass
        @property                      #属性
        def prop(self):               
            pass
    

    十二.类的私有成员

    无论是类的私有属性还是私有方法,都只能在本类内部调用,注意是本类内部。外部和此类的子类都不能调用。如果要想一个变量或方法变成私有的,在前面加上__即可,这样打印a.dict,我们可以得到对象a的空间的属性,私有属性默认为设为_A__name,可通过此字段访问私有属性,但建议不要这样做。

    1.私有静态字段

    # 类内部可访问
    class A:
        name = "公有静态字段"
        __name = "私有静态字段"
        
        def func(self):
            print(self.name)
            print(self.__name)
            
    a = A()
    a.func()  #打印结果:共有静态字段 私有静态字段
    
    
    # 外部不可访问
    class A:
        __name = "私有静态字段"
    
    a = A()
    print(a.__name)  # 报错,提示对象a没有此__name属性
    
    
    # 类的子类不能访问
    class A:
        __name = "私有静态字段"
    class B:
        def func(self):
            print(self.__name)
    
    b = B()
    b.func()   # 报错,提示对象b没有__name属性
    

    2.私有方法

    # 类内部可访问
    class A:
        def __func(self):
            print("类的私有方法")
        def func(self):
            self.__func()
    a = A()
    a.func() # 打印结果: 类的私有方法
    
    
    # 外部不可访问
    class A:
        def __func(self):
            print("类的私有方法")
    a = A()
    a.__func()  # 报错,提示对象a没有__func属性
    
    
    # 类的子类不能访问
    class A:
        def __func(self):
            print("类的私有方法")
    class B(A):
        def func(self):
            self.__func()
    b = B()
    b.func()    # 报错,提示b对象没有__func属性
    

    3.私有对象属性

    class A:
        def __init__(self,name,sex):
            self.name = name 
            self.__sex = sex
    a = A("小明","男")
    print(a.__sex)    # 报错,提示对象a没有__sex属性
    print(a.__dict__) # {'name': '小明', '_A__sex': '男'}
    

    十三.类的其他成员

    类的其他成员中包括实例方法、类方法、静态方法、双下方法。

    1.类方法

    一般通过类名调用的方法,并且自动将类名地址传给参数cls。通过实例化对象调用也可以,还是将对象所属类名地址也传给cls。

    类方法作用:1.得到类名可以实例化对象。2.可以操作类的属性

    # 得到实例化对象的个数
    class Student:
        count = 0 
        def __init__(self,name,id):
            self.name = name
            self.id = id
            
        @classmethod
        def addnum(cls):
            cls.count = cls.count + 1
        
        @classmethod
        def getnum(cls):
            return cls.count
    
    obj1 = Student('liye', 12343243243)
    obj1 = Student('liye', 12343243243)
    print(Student.getnum()) # 2
    

    2.静态方法

    使用装饰器@staticmethod

    静态方法主要用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系。

    静态方法作用:1.代码更加规范、合理。2.它仅仅托管于某个类的名称空间中,便于使用和维护。

    import time
    
    class TimeTest(object):
    
        area = '中国'
        def __init__(self, hour, minute, second):
            self.hour = hour
            self.minute = minute
            self.second = second
    
        def change_time(self):
            print(f'你想调整的时间: {self.hour}时{self.minute}分{self.second}秒')
    
        @staticmethod
        def showTime():
            return time.strftime("%H:%M:%S", time.localtime())
    
    
    def showTime():
        return time.strftime("%H:%M:%S", time.localtime())
    
    def time1():
        pass
    
    def time2():
        pass
    # t = TimeTest(2, 10, 10)
    # # t.change_time()
    # print(TimeTest.showTime())
    

    十四.特性property

    应用场景:遇到类似于属性的方法名,可以让其伪装成属性

    以下两个方法都是将动态方法伪装成一个属性

    1.利用装饰器设置属性

    class Foo:
        @property
        def bmi(self):
            print("get的时候运行")
        
        @bmi.setter
        def bmi(self,value):
            print("set的时候运行")
        
        @bmi.deleter
        def bmi(self):
            print("delete的时候运行")
            
    foo = Foo()
    foo.bmi           # 执行@property装饰的方法
    foo.bmi = 666     # 不是改变bmi的值,而是执行setter装饰的方法
    del foo.bmi       # 执行deleter装饰的方法
    

    2.利用实例化对象的方式设置属性

    class Foo:
        def get_A(self):
            print("get的时候运行")
        def set_A(self):
            print("set的时候运行")
        def delete_A(self):
            print("delete的时候运行")
        A = property(get_A,set_A,delete_A)   # 内置property三个参数与get,set,delete
    
    f1 = Foo()
    f1.A              # 执行get_A()函数
    f1.A = 'aaa'      # 执行set_A()函数
    del f1.A          # 执行delete_A()函数
    

    十五.isinstance,issubclass

    1.isinstance(对象与类的关系)

    判断对象是否是某类某类派生类的实例化对象

    class A:
        pass
    class B(A):
        pass
    
    obj = B()
    print(isinstance(obj,B))  # True
    print(isinstance(obj,A))  # True
    

    2.issubclass(类与类的关系)

    判断是否是某类某类派生类派生类

    class A:
        pass
    class B(A):
        pass
    class C(B):
        pass
    
    issubclass(B,A)    # True
    issubclass(C,A)    # True
    
  • 相关阅读:
    前缀判断 蓝桥杯
    dedecms 网站内容静态化和动态化的切换
    dedecms 频道标签 channel.lib.php的分析
    JavaScript通过闭包解决只能取得包含函数中任何变量最后一个值的问题
    JavaScript闭包 取for循环i 【转】
    JavaScript装饰模式
    JavaScript闭包意义谈
    JavaScriptjs闭包测试
    JavaScript闭包的作用谈(转)
    Zend Engine 简介
  • 原文地址:https://www.cnblogs.com/luckinlee/p/11620350.html
Copyright © 2020-2023  润新知