• python基础 面向对象编程


    目录

    面向对象编程

    1.什么是面向对象编程?

    面向过程编程思想

    核心是 过程 二字, 过程指的是解决问题的步骤,即先干什么再干什么
    基于该编程思想编写程序,就好比在设计一条工厂流水线,一种机械式的思维方式。
    
    

    面向过程编程优缺点:

    优点:
    将复杂的问题流程化,进而简单化
    
    缺点:
    牵一发而动全身,可扩展性差
    

    面向对象编程思想

    核心是 对象 二字,对象指的是 特征(属性/变量)与技能(方法/函数)的结合体。基于该编程思想编写程序,就好比在创造世界,一种上帝式的思维方式。
    

    面向对象编程思想优缺点:

    优点:
    可扩展性强。(只需要关注对象能干什么拥有什么特征,无需关注他做事情的步骤)
    
    缺点:
    编写的复杂难度较高于面向过程编程思想。
    
    注意: 在生产开发中,两种编程思想相辅相成,缺一不可!
    

    2.什么是类?如何定义。

    类:

    类指的是类型类别。

    对象

    对象是 特征与技能 的结合体, 类是一系列对象相同的 特征与技能 的结合体。
    

    要定义类时

    要定义类: 先抽象,再定义。
    

    现实世界中:

    先有对象,然后再有类。
    

    在程序中:

    先定义类,后调用用类产生对象。
    

    对象的特征和技能

           - 对象1:
                - 特征:
                    - name: hcy
                    - age: 84
                    - sex: female
                    - school = 'oldboy'
    
                - 技能:
                    - 漂泊十年无需用一毛
                    - 学习
    
            - 对象2:
                - 特征:
                    - name: JP
                    - age: 95
                    - sex: male
                    - school = 'oldboy'
    
                - 技能:
                    - 澳门赌场上线首席发牌师
                    - 学习
    
            - 学生类:
                - 相同的特征
                    - school = 'oldboy'
    
                - 相同的技能
                    - 学习
    
            class 类名:
                school = 'oldboy'
    
                def learn(self):
                    print('learning...')
    
    

    3.如何产生对象?

     - 调用类产生对象
          语法: 类名 + () 调用
    
    - 调用类的过程: 称之为类的实例化,产生的对象称之为类的一个实例。
    
    - 调用类时发生的事情:
    1) 产生一个空对象的名称空间
    2) 自动触发类内容__init__方法的执行。
    3) 会将对象本身当做第一个参数,以及调用类括号内所有的参数并传给__init__。
    
    

    代码

    class Student:
        # 学校
        school = 'oldboy'
    
        def __init__(self, name, sex, age):  # stu1, 'tank', 'male', 17
            print(self.__dict__)  #{}
    
            # 给对象添加新的属性
            self.name = name  # stu1.x = 'tank'
            self.sex = sex  # stu1.y = 'male'
            self.age = age  # stu1.z = 17
    
            # 查看当前对象的名称空间
            print(self.__dict__)  #{'name': 'wang', 'sex': 17, 'age': 'male'}
        # 学习技能   ----> method ---》 方法
        def learn(self):
            print(self)  #
            print('learning...')
    
    # 查看类的名称空间
    print(Student.__dict__)
    
    stu1 = Student('wang',17,'male') 
    stu1.learn()  #learning...
    
    stu1.name = '江鹏'
    stu1.sex = 'female'
    stu1.age = 84
    print(stu1.name, stu1.sex, stu1.age)  #江鹏 female 84
    
    
    ## 结果:
    {'__module__': '__main__', 'school': 'oldboy', '__init__': <function Student.__init__ at 0x0000028C5598E3A8>, 'learn': <function Student.learn at 0x0000028C5598E9D8>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}
    
    {}
    
    {'name': 'wang', 'sex': 17, 'age': 'male'}
    
    <__main__.Student object at 0x0000028C64A07DC8>
    
    learning...
    
    江鹏 female 84
    

    调用类时的事件:

    调用类会时,自动触发__init__,然后产生一个对象,会将对象第一个参数传给—__init__,也就是self。 # self相当于就是p_obj对象
    并将调用类括号中的参数一并传给__init__()
    
    class People:
        country = 'China'
        def __init__(self, name, age, sex):  # self相当于就是p_obj对象
            print(self.__dict__)   #{}
            print(self)            # <__main__.People object at 0x0000022D8C569548>
            self.name = name
            self.age = age
            self.sex = sex
            print(self.__dict__) #{'name': 'tank', 'age': 17, 'sex': 'male'}
    
        # 注意: 看到self就应该知道是对象本身
        def learn(self):
            print('learning....')
    
    
    p_obj = People('tank', 17, 'male')
    p_obj.learn() #learning....
    
    结果:
    {}
    <__main__.People object at 0x0000022D8C569548>
    {'name': 'tank', 'age': 17, 'sex': 'male'}
    learning....
    
    

    4.对象属性的查找顺序:

    对象名字的查找顺序:  *******
        1.对象.属性,会先找对象自己的。
        2.若对象没有,会去找类的。
        3.若类没有,则会报错。
    class People:
        country = 'China'
        name = 'jason'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def run(self):
            print('running...')
    
    
    obj1 = People('tank', 17, 'male')
    print(obj1.name)  # tank  找对象自己的name属性
    print(obj1.country)  # China  对象没有,找类中的属性
    
    # print(obj1.jason)  # 对象没有,类也没有,就会报错!
    print(obj1.__dict__)
    # 给对象的名称空间添加 country='中国' 属性
    obj1.country = '中国'
    print(obj1.__dict__)
    print(People.__dict__)
    print(obj1.country)
    
    
    

    5.类内部的函数:

    - 由类来调用的方法,就是一个普通函数,函数需要几个参数,就得传入几个参数。
    - 由对象来调用,就是一个对象的绑定方法,由不同的对象调用就会绑定给不同的对象,称之为对象的绑定方法。
    

    一切皆对象

    比如: python的八大数据类型都是类
                定义数据类型的值时,内部自动调用响应的类,然后产生对象。
            
            
    class Foo:
        def __init__(self, x, y, z):
            self.x = x
            self.y = y
            self.z = z
    
    
    # 产生对象
    # 调用类产生对象的过程称之为类的实例化,对象称之为类的一个实例。
    foo_obj = Foo(10, 20, 30)
    print(foo_obj) #<__main__.Foo object at 0x000002072717A248>
    

    人狗大作战

    需求:
                - 先有人类,狗类,调用人类与狗类,产生两个对象、
                - 一个是人对象,一个是狗对象,人狗互咬。
    class People:
    
        def __init__(self, name, life, arg):
            self.name = name
            self.life = life
            self.arg = arg
    
        # 人调用bite时,传入狗对象
        def bite(self, dog_obj):
            print(f'人:[{self.name}] 开始 咬 狗:[{dog_obj.name}]!')
    
            # 减掉狗对象中的生命值  值为人的攻击力
            dog_obj.life -= self.arg
            print(f'狗的生命值减掉: [{self.arg}], 还剩狗的血量: [{dog_obj.life}]')
    
            if dog_obj.life <= 0:
                print(f'狗[{dog_obj.name}]已经挂了')
                return True
    
    
    
    # 狗类
    class Dog:
        def __init__(self, name, life, dog_type, arg):
            self.name = name
            self.dog_type = dog_type
            self.life = life
            self.arg = arg
    
        # 狗对象调用bite时,传入人对象
        def bite(self, p_obj):
            print(f'狗:[{self.name}] 开始 咬人:[{p_obj.name}]!')
    
            # 减掉人对象中的生命值  值为狗的攻击力
            p_obj.life -= self.arg
            print(f'人的生命值减掉: [{self.arg}], 还剩人的血量: [{p_obj.life}]')
    
            if p_obj.life <= 0:
                print(f'人[{p_obj.name}]已经挂了')
                return True
    
    
    p1 = People('高弟', 2000, 500)
    d1 = Dog('HCY', 2500, '哈士奇', 250)
    
    p2 = People('高弟2', 5000, 50)
    import time
    
    while True:
        # 开始人狗互咬
        # if p1.life or d1.life:
        res1 = d1.bite(p2)
    
        if res1:
            break
    
        time.sleep(1)
    
        res2 = p1.bite(d1)
    
        if res2:
            break
    
        time.sleep(1)
    

    继承

    1.什么是继承?

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

    2.继承的好处?

    减少代码冗余(减少重复代码)
    

    3.如何继承?

    - 确认继承关系
        - 先抽象,再继承
              - 类是抽取一系列对象相似的部分
              - 父类是抽取一系列类相似的部分
    
         - 父类
         - 子类
        - 语法:
              class 子类(父类):
    

    4.继承背景下,对象.属性的查找顺序

    1.先从对象的名称空间中查找
    2.若对象中没有,去子类中查找
    3.若子类中没有,去父类中查找
    
    

    5.派生:

    派生: 子类继承父类,派生出自己的属性和方法。
    

    6.重用父类的属性与方法,并派生出自己的属性与方法。

    - 直接调用父类中__init__(self)
    
    - super().__init__()
    

    7.新式类与经典类

    - 新式类
      - 所以继承object的类,以及子孙类都称之为新式类。
    
    - 经典类
      - 没有继承object的类,都是经典类。
    
    

    8.钻石继承(菱形继承)背景下,属性查找顺序

    经典类: 深度优先
    新式类: 广度优先
    

    9..mro: 类的内置方法

    类.mro()
    super严格依赖mro继承序列的顺序
    

    1.组合

    是什么组合?

    组合是一个对象中,包含另一个或多个对象。
    

    组合的好处(作用)

    减少代码冗余 (减少重复代码),提高开发效率。
    

    组合与继承相比?

    耦合度低,程序的可扩展性高。
    耦合度高,程序的可扩展性低。
    

    组合如何实现?

    class User:
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def run(self):
            print('user running...')
    
    
    class Date:
        def __init__(self, year, month, day):
            self.year = year
            self.month = month
            self.day = day
    
        def print_birth(self):
            print(
                self.year,
                self.month,
                self.day
            )
    
    
    user_obj = User('WH', 20, 'male')
    date_obj = Date(1999, 11, 11)
    user_obj.date_obj = date_obj
    
    user_obj.date_obj.print_birth()
    
    #1999 11 11
    

    2.封装:

    什么是封装?

    将一堆属性与方法 封装 到对象中。
    
    封: 比如:将袋子封起来
    装:比如: 将一堆小猫、小狗、HCY装进袋子里
    将一堆属性与方法 封装 到对象中。
    

    3.访问限制机制

    访问限制机制是什么

    凡是在类内部定义的,以__开头的属性或方法,都不能被外部 “直接访问”。
    - 若想访问: (强烈不推荐)
    	 _类名__属性/方法
    

    访问限制机制作用

    可以将隐私的数据,隐藏起来,可以让调用者通过接口来获取。
    接口中可以做一些逻辑处理,限制调用者的访问
    可以保证数据安全。
    

    如何用访问限制机制?

    class User:
      __属性 = 属性值
    
      def __方法(self):
          pass
    
    
          def inf(self):
          # 逻辑的处理
          # 用户访问的限制
          return self.__属性
    
    
    # 列题:
    class ATM:
        # 取钱功能:
        # 1.插入磁卡
        def __insert_card(self):
            print('开始插卡...')
            pass
    
        # 2.输入密码
        def __input_pwd(self):
            print('输入密码...')
            pass
    
        # 3.输入取款金额
        def __input_bal(self):
            print('输入取款金额...')
            pass
    
        # 4.吐钱
        def __output_money(self):
            print('开始吐钱...')
            pass
    
        # 5.打印流水账单
        def __print_flow(self):
            print('打印流水账单...')
            pass
    
        # 取款顺序规范接口:
        def withdraw(self):
            # 1.插入磁卡
            self.__insert_card()
    
            # 2.输入密码
            self.__input_pwd()
    
            # 3.输入取款金额
            self.__input_bal()
    
            # 4.吐钱
            self.__output_money()
    
            # 5.打印流水账单
            self.__print_flow()
    
    
    amt_obj = ATM()
    amt_obj.withdraw()
    

    访问限制机制需注意

    接口只能在 “__属性/方法” 的类中返回 “__属性/方法”。
    

    4.property装饰器

    property 作用:

    可以将 def 方法() ---> 在调用时  对象.方法() -----> 对象.方法。
    迷惑用户,让用户误以为调用的方法是一个属性。
    

    property 如何使用:

    		@property
             def get_name(self):
                 return self.name
    
             print(obj.get_name)  # obj.get_name()
    
    # 需求: 计算人体 bmi 指数
    # 体重 / 身高的平方
    # value = weight / (height * height)
    class User:
        def __init__(self, name, weight, height):
            self.__name = name
            self.weight = weight
            self.height = height
    
        # 获取bmi指数方法
        @property
        def bmi(self):
            # return self.weight / (self.height * self.height)
            return self.weight / (self.height ** 2)
    
    
        @property
        def name(self):
            return self.__name
    
        # 了解: 设置被property装饰后的方法
        # 注意: 需要修改的方法名字要与被property装饰器后的方法一样
      # @name.setter
      # def name(self, value):  # '赵shuai兵' --- 》 value
      #     self.__name = value
    
      # @name.deleter
      # def name(self):  # 删除属性
      #      del self.__name
    
    
    user_obj = User('HCY', 100, 1.9)
    
    # user_obj.bmi()()
    # print(user_obj.bmi())
    
    
    # user_obj.bmi()
    print(user_obj.bmi)
    

    1.多态

    什么是多态?

    指的是同一事物的多种形态。
    

    多态什么用?

    多态也称之为多态性,在不知道具体对象的情况下,统一对象调用相似方法的规范(名字)。
    

    多态的表现形式:

    继承

    先抽象,再继承
    

    父类:

    定制一套统一的规范。
    

    子类

    遵循父类统一的规范。
    

    遵循代码:

    # 正面教材
    - 动物(父类):
                        - eat、speak、run
    
    
                    - 猪、猫、狗(子类):
                        - eat、speak、run
    
                        # 反面教材
                        - chi、jiao、pao
    # 列:
    # 动物类
    class Animal:
    
        # 方法 吃
        def eat(self):
            pass
    
        # 方法 叫
        def speak(self):
            pass
    # 猪类
    class Pig(Animal):
        def eat(self):
            print('bia唧...')
    
        def speak(self):
            print('哼哼哼...')
            
    # 猫类
    class Cat(Animal):
        def eat(self):
            print('咬ji 咬ji....')
    
        def speak(self):
            print('喵喵喵...')
    
    # 狗类
    class Dog(Animal):
        def eat(self):
            print('舔 ji 舔ji...')
    
        def speak(self):
            print('汪汪汪...')
    
    animal1 = Dog()
    animal2 = Pig()
    animal3 = Cat()
    
    # 让动物们叫起来
    animal1.speak()
    animal2.speak()
    animal3.speak()
    
    #结果
    汪汪汪...
    哼哼哼...
    喵喵喵...
    

    缺点:

    耦合度高,程序的可扩展性低。
    
    注意
    在python中是不会强制子类必须要遵循父类的规范,所以出现了抽象类。
    

    2.抽象

    什么是抽象?

    在python内置的abc模块中,有一个抽象类(abc.ABCMeta)
    

    抽象作用

    只要父类继承了抽象类
    子类就必须要遵循父类的规范
    父类有几个抽象方法,子类就必须有几个一摸一样的方法。
    
    注意:
    注意: 在python中不推荐使用抽象类。
    
    注意: 子类必须按照父类的方法编写规范,缺一不可。(只要父类中有几个抽象方法,子类就必须要定义几个)
    '''
    

    如何实现

    import abc
    
    # 父类
    class Animal(metaclass=abc.ABCMeta):
        # 方法 吃
        @abc.abstractmethod
        def eat(self):
            pass
        # 方法 叫
        @abc.abstractmethod
        def speak(self):
            pass
    # 猪类
    
    class Pig(Animal):
        def run(self):
            pass
    
        def eat(self):
            print('bia唧...')
    
        def speak(self):
            print('哼哼哼...')
    
    pig_obj = Pig()
    pig_obj.eat()  #bia唧...
    
    # 如果掉用装饰后的值就报错(不能用抽象类的方法实例化抽象类动物) 因为他只是一个模板,装饰后,子类必须遵寻父类的值,父类的值跑了子类,覆盖子类,所以掉用子类。子类就必须要遵循父类的规范,父类有几个抽象方法,子类就必须有几个一摸一样的方法。
    #
    # pig_obj=Animal()
    # pig_obj.eat()
    

    缺点

    耦合度极高,程序可扩展性极低。
    

    鸭子类型

    什么是鸭子类型?

    只要对象长得像鸭子,行为举止也像鸭子,比如: 游泳,吃鱼, 所以他就是鸭子
    

    为什么要有鸭子类型?

    2.为什么要有鸭子类型?
        不同对象,先抽象出相同类型的方法,给他们定制一套统一的规范。
        所有的类,在定义时都按照统一的规范进行编写。
    
        - 多态的三种表现形式:
            - 继承父类    ****
                - 耦合度高,程序的可扩展性低
    
            - 继承抽象类  ***
                - 耦合度极高,程序的可扩展性极低
    
            - 鸭子类型:   *****
                - 耦合度低,程序的可扩展性高
    
        注意: 在python中,强烈推荐使用鸭子类型。
    

    鸭子类型的作用?

    - 在定义类之前,先定制一套鸭子类型的规范。
    - 所有开发者都按照这套规范来定义类中的方法。
    

    优点:

    耦合极低,程序的可扩展性高。
    

    缺点:

    造成了代码的冗余
    

    如何实现

    # 猪类
    class Pig:
        def eat(self):
            print('bia唧...')
    
        def speak(self):
            print('哼哼哼...')
    
    # 猫类
    class Cat:
        def eat(self):
            print('咬ji 咬ji....')
    
        def speak(self):
            print('喵喵喵...')
    
    # 狗类
    class Dog:
        def eat(self):
            print('舔 ji 舔ji...')
    
        def speak(self):
            print('汪汪汪...')
    

    4.isinstance与issubclass

    isinstance:判断一个对象是否是一个类的实例。
    - 如果是: True
            - 如果不是: False
    - issubclass:判断一个子类是否是另一个类的子类。
           - 如果是: True
            - 如果不是: False
    

    如何使用:

    # isinstance:
    class Foo:
        pass
    
    class Boo:
        pass
    
    foo_obj = Foo()
    boo_obj = Boo()
    
    print(isinstance(foo_obj, Foo))  # True
    print(isinstance(boo_obj, Foo))  # False
    
    # issubclass
    class Father:
        pass
    
    class Sub(Father):
        pass
    
    class Foo:
        pass
    
    print(issubclass(Sub, Father))  # True
    print(issubclass(Foo, Father))  # False
    

    5.classmethod与staticmethod

    classmethod:

    是一个装饰器,可以装饰在类内部的方法中,将该方法变成类的绑定方法。
    
    class Dog():
        def eat(self):
            print('狗狗吃饭饭。。。')
    
    class Pig():
        @classmethod  # 将此方法对象绑定
        def eat(self):
            print('猪猪看电视。。。')
    
    # 对象绑定方法,需要实例化出一个对象
    keji = Dog()
    keji.eat()
    
    # 类绑定方法,不需要对象,直接通过类
    zhu = Pig.eat()
    
    # 列二:进阶高级
    class DB:
        __data = 'jeff is very handsome!!!'
        def __init__(self, user, pwd, role):
            self.user = user
            self.pwd = pwd
            self.role = role
            
        # 查看数据方法
        @classmethod  # 类绑定
        def check_db(cls, user, pwd, role):  # cls --》指的是类
            # 在类方法内部调用类产生一个实例 ---》 对象
            obj = cls(user, pwd, role)    # 再类的内部实例化出一个对象,供内部使用
    
            # 1.查看数据前,必须要通过校验
            if obj.user == 'tank' and obj.pwd == '123' and obj.role == 'admin':
                print('检验通过..')
                print(cls.__data)
                return cls.__data
            
    # 类绑定方法了
    DB.check_db('tank', '123', 'admin')
    #  结果:
    检验通过..
    jeff is very handsome!!!
    

    staticmethod(静态方法):

    是一个装饰器,可以装饰在类内部的方法中,将该方法变成非绑定方法。
    
    1.不用非绑定方法,打印的是func函数的地址
    class Foo:
        def func(res):
            print(res)
    obj = Foo()
    obj.func()
    #  <__main__.Foo object at 0x000001FF9F5D82E8>
    
    2.对象调用非绑定方法
    class Foo:
        @staticmethod
        def func(res):
            print(res)
    # 产生了obj对象
    obj = Foo()
    obj.func(123)  # 123
    
    3.类直接调用非绑定方法
    class Foo:
        @staticmethod
        def func(res):
            print(res)
    Foo.func(1234)
    #  1234
    

    绑定方法:

    对象的绑定方法:

    - 对象的绑定方法: (在类内部定义(封装)一个方法即可)
    由对象来调用,对象来调用,会将对象当做第一个参数传入给该方法。
    
    class OldboyStudent:
        school = 'oldboy'
    
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.sex = gender
    
        def choose_course(self):
            print(f'{self.name} choosing course')
    
        def func(self):
            print('from func')
          
    stu1 = OldboyStudent('nick', 18, 'male')
    stu2 = OldboyStudent('sean', 17, 'male')
    stu3 = OldboyStudent('tank', 19, 'female')
    
    print(stu1.name)   # nick
    print(stu1.school)   # oldboy
    2.类的绑定方法@classmethod
    

    类的绑定方法:

    - 类的绑定方法:   (在类内部方法中,使用classmethod装饰器即可)
    由类来调用,类来调用,会将类当做第一个参数传入给该方法。
    

    classmethod:

    是一个装饰器,可以装饰在类内部的方法中,将该方法变成类的绑定方法。
    
    class Dog():
        def eat(self):
            print('狗狗吃饭饭。。。')
    
    class Pig():
        @classmethod  # 将此方法对象绑定
        def eat(self):
            print('猪猪看电视。。。')
    
    # 对象绑定方法,需要实例化出一个对象
    keji = Dog()
    keji.eat()
    
    # 类绑定方法,不需要对象,直接通过类
    zhu = Pig.eat()
    
    # 列二:进阶高级
    class DB:
        __data = 'jeff is very handsome!!!'
        def __init__(self, user, pwd, role):
            self.user = user
            self.pwd = pwd
            self.role = role
            
        # 查看数据方法
        @classmethod  # 类绑定
        def check_db(cls, user, pwd, role):  # cls --》指的是类
            # 在类方法内部调用类产生一个实例 ---》 对象
            obj = cls(user, pwd, role)    # 再类的内部实例化出一个对象,供内部使用
    
            # 1.查看数据前,必须要通过校验
            if obj.user == 'tank' and obj.pwd == '123' and obj.role == 'admin':
                print('检验通过..')
                print(cls.__data)
                return cls.__data
            
    # 类绑定方法了
    DB.check_db('tank', '123', 'admin')
    #  结果:
    检验通过..
    jeff is very handsome!!!
    

    非绑定方法:

    - 非绑定方法:     (在类内部方法中,使用staticmethod装饰器即可)
    由对象/类来调用,由谁来调用,它都是一个普通函数,内部需要接受几个参
    
    class OldboyStudent:
        school = 'oldboy'
    
        def __init__(self, name, age, gender):
            self.name = name
            self.age = age
            self.sex = gender
    
        def choose_course(self):
            print(f'{self.name} choosing course')
    
        def func(self):
            print('from func')
          
    stu1 = OldboyStudent('nick', 18, 'male')
    stu2 = OldboyStudent('sean', 17, 'male')
    stu3 = OldboyStudent('tank', 19, 'female')
    
    print(stu1.name)   # nick
    print(stu1.school)   # oldboy
    2.类的绑定方法@classmethod
    

    6.反射:

    什么是反射?

    通过 “字符串” 对 对象的属性或方法进行操作。
    

    语法

    - hasattr: 通过 字符串 判断对象的属性或方法是否存在,存在返回True, 否则返回False。
    hasattr(对象, '对象的属性或方法字符串')
    
    - getattr: 通过 字符串 获取对象的属性或方法是否存在,存在返回获取属性或方法, 否则返回报错。
    getattr(对象, '对象的属性或方法字符串', '默认值')
                - 若设置默认值,没有则返回默认值
    - setattr: 通过 字符串 设置(添加/修改)对象的属性或方法。
    setattr(对象, '对象的属性或方法字符串', '属性的值')
    
    - delattr: 通过 字符串 删除 对象的属性或方法,若属性不存在,则报错。
    delattr(对象, '对象的属性或方法字符串')
    
    

    如何使用

    # 反射应用:
    class FileControl:
    
        def run(self):
            while True:
                # 让用户输入上传或下载功能的命令:
                user_input = input('请输入 上传(upload) 或 下载(download) 功能:').strip()
    
                # 通过用户输入的字符串判断方法是否存在,然后调用相应的方法
                if hasattr(self, user_input):
                    func = getattr(self, user_input)
                    func()
                else:
                    print('输入有误!')
    
        def upload(self):
            print('文件正在上传...')
    
        def download(self):
            print('文件正在下载...')
    
    
    file_control_obj = FileControl()
    file_control_obj.run()
    

    .反射

    反射使用场景:
    
       1.反射就是对属性的增删改查,但是如果直接使用内置的 dict来操作,语法繁琐,不好理解
            2.如果对象是别人提供的,判断这个对象是否满足要求
    
    hasattr(p,'name'):查找p对象中是否存在name属性
    getattr(p,'name'):取值,p对象中name属性
    setattr(p,'name','jeff'):添加,为p对象中添加name属性jeff
    delattr(p,'name'):删除,删除p对象中name属性
    

    img

    1、hasattr: 查找-反射

    foo_obj对象中是否存在x属性

    class Foo:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    foo_obj = Foo(10, 20)
    # 通过字符串x 判断对象中是否有 x属性
    print(hasattr(foo_obj, 'x'))  # True
    print(hasattr(foo_obj, 'z'))  # False
    

    2、getattr :取值 反射

    getattr(foo_obj,'x'):取值p对象中name属性

    class Foo:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
    foo_obj = Foo(10, 20)
    
    res = getattr(foo_obj, 'x')
    print(res)  # 10
    

    3、setattr: 添加-反射

    为foo_obj对象中添加z属性30

    class Foo:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
    foo_obj = Foo(10, 20)
    
    
    setattr(foo_obj, 'z', 30)  # 为对象添加z属性值为30
    print(hasattr(foo_obj, 'z'))  # True
    

    4、delattr: 删除-反射

    删除foo_obj对象中x属性

    class Foo:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
    foo_obj = Foo(10, 20)
    
    delattr(foo_obj, 'x')  # 删除对象中x属性
    print(hasattr(foo_obj, 'x'))  # False
    

    5.反射应用

    通过用户输入的字符串,判断是否存在,getattr取值,加括号调用相应的功能函数

    class FileControl:
    
        def run(self):
            while True:
                # 让用户输入上传或下载功能的命令:
                user_input = input('请输入 上传(upload) 或 下载(download) 功能:').strip()
    
                # 通过用户输入的字符串判断方法是否存在,然后调用相应的方法
                if hasattr(self, user_input):
                    func = getattr(self, user_input)
                    func()
                else:
                    print('输入有误!')
    
        def upload(self):
            print('文件正在上传...')
    
        def download(self):
            print('文件正在下载...')
    
    file = FileControl()
    file.run()
    

    类的内置方法(魔法方法)

    魔法归总

    类的内置方法(魔法方法):
        凡是在类内部定义,以__开头__结尾的方法,都是类的内置方法,也称之为魔法方法。
        类的内置方法,会在某种条件满足下自动触发。
    
    内置方法如下:
        __new__: 在__init__触发前,自动触发。  调用该类时,内部会通过__new__产生一个新的对象。
        __init__: 在调用类时自动触发。    通过产生的对象自动调用__init__()
        __getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。
        __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
            # 注意: 只要__getattr__ 与 __getattribute__ 同时存在类的内部,只会触发__getattribute__。
       __setattr__:当 “对象.属性 = 属性值” , 添加或修改属性时触发
       __call__ : 在调用对象 “对象 + ()” 时触发。 即:对象() 或者 类()()
       __str__  : 在打印对象时触发。 # 注意: 该方法必须要有一个 “字符串” 返回值。
       __getitem__: 在对象通过 “对象[key]” 获取属性时触发。
       __setitem__: 在对象通过 “对象[key]=value值” 设置属性时触发。
       __gt__,__lt__,__eq__:自定义比较对象大小双下:gt、lt、eq
       __enter__:  进入文件时,开打文件时执行。返回值:self
       __exit__:  退出文件时,报错中断、或者代码执行完时执行。 返回值:可以有返回值,是bool类型
       __del__ : 手动删除时立马执行,或者程序运行结束时自动执行
                使用场景:当你的对象使用过程中,打开了不属于解释器的资源;例如,文件,网络端口
       __slots__:原理,给对象声明只有某些属性,从而删除不必要的内存,不能添加新属性
                使用场景:1.优化对象内存  2.限制属性数量
    

    1.双下new

    因为类继承了object,所有在调用类之前会自动先执行双下new来创建对象。这里的双下new重写了object中的双下new,所以此时不能创建出对象。
    class Demo():
        def __new__(cls, *args, **kwargs):
            print('此处是__new__方法的执行')
            # python内部通过object调用内部的__new__实现产生一个空的对象  ---> 内存地址
    
        def __init__(self):
            print('此处是__init__方法的执行')
    # 只是实例化对象
    demo_obj = Demo()
    # 结果:
    此处是__init__方法的执行
    

    2.双下getattr

    双下getattr: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。
    class Demo():
        # __getattr__: 在 “对象.属性” 获取属性时,若 “属性没有” 时触发。
        def __getattr__(self, item):
            print('此处是__getattr__方法的执行')
            print(item)
    
            # return 想要返回的值
            return 'tank is very very handsome!!!'
    
    demo_obj = Demo()
    res = demo_obj.x  # 获取属性,赋值
    # 打印返回值
    print(res)
    # 结果:
    此处是__getattr__方法的执行
    x
    jeff is very very handsome!!!
    

    3.双下getattribute

     # 条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
        
        class Demo():
        # 条件: __getattribute__: 在 “对象.属性” 获取属性时,无论 "属性有没有" 都会触发。
        def __getattribute__(self, item):
            print(item, '<-----打印属性名字')
            # print(self.__dict__)
            # return self.__dict__[item]
            # 注意: 此处不能通过 对象.属性,否则会产生递归调用,程序崩溃
            # getattr: 内部调用了 ----> __getattribute__
            # return getattr(self, item)
    
    demo_obj = Demo()
    demo_obj.x
    
    # 结果:
    x <-----打印属性名字
    

    4.双下setattr

    # __setattr__:当 “对象.属性 = 属性值” , 添加或修改属性时触发
    
    class Demo():
        y = 20
        def __setattr__(self, key, value):
            print('此处是__setattr__方法的执行')
            print(key, value)
            
            # 循环递归,报错
            # self.key = value
            
    jeff = Demo()
    jeff.y = 10
    # 结果:
    此处是__setattr__方法的执行
    y 10
    

    5.双下call

    # 注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 双下__call__ 方法的执行是由对象后加括号触发的.
    # 即:对象() 或者 类()()
    
    class Demo():
        def __call__(self, *args, **kwargs):
            print('此处是__call__方法的执行')
    
            # 调用对象时返回的值
            return [1, 2, 3, 4, 5]
        def y(self):
            pass
    
    jeff = Demo()
    jeff()
    # 结果:
    此处是__call__方法的执行
    

    6.双下str

    # __str__  : 在打印对象时触发。 # 注意: 该方法必须要有一个 “字符串” 返回值。
    # print 时内部自动调用__str__
    class Demo():
        def __str__(self):
            res = '此处是__str__方法的执行'
            # 必须有返回值
            return res
    
    jeff = Demo()
    print(jeff)
    # 结果:
    此处是__str__方法的执行
    

    7.双下getitem

    # 在对象通过 “对象[key]” 获取属性时触发。
    class Demo():
        def __getitem__(self, item):
            print('此处是__getitem__方法的执行')
            print(item)
    
    jeff = Demo()
    jeff['y']
    # 结果:
    此处是__getitem__方法的执行
    y
    

    8.双下setitem

    # 在对象通过 “对象[key]=value值” 设置属性时触发。
    
    class Demo():
        def __setitem__(self, key, value):
            print('此处是__setitem__方法的执行')
            print(key, value)
    
            print(self.__dict__)
            self.key = value  # {'key': value}   {'key': 123}
            print(self.__dict__)  # 
    
    jeff = Demo()
    jeff['y'] = 123
    # 结果:
    此处是__setitem__方法的执行
    y 123
    {}
    {'key': 123}
    

    9.自定义比较对象大小双下:gt、lt、eq

    可以利用这三个自定义比较对象:
    __gt__:greater than  大于缩写
    __lt__:less than  小于缩写
    __eq__:equal   等于缩写
    class Student(object):
        def __init__(self, name, height, age):
            self.name = name
            self.height = height
            self.age = age
    
        # 比较大于时触发
        def __gt__(self, other):
            return self.height > other.height
    
        # 比较小于时触发
        def __lt__(self, other):
            return self.age < other.age
    
        # 比较等于时触发
        def __eq__(self, other):
            # if self.age == other.age:  # 比较两个对象的年龄
            if self.age == other.age and self.height == other.height:  # 比较年龄和身高
                return '年龄身高一样'
            return '年龄身高不一样'
    
    
    stu1 = Student("jeff", 170, 25)
    stu2 = Student("make", 170, 25)
    
    print(stu1 > stu2)
    print(stu1 < stu2)
    print(stu1 == stu2)
    

    10.上下文管理双下enter进入文件时,双下__exit__离开

    # __enter__:1.进入文件,开打文件时执行
                2.函数应该返回自己self
    # __exit__:1.退出文件、报错中断、或者代码执行完时执行
            2.可以有返回值,是bool类型
            
    class MyOpen(object):
        def __init__(self, path):
            self.path = path
        
        # 进入文件时触发
        def __enter__(self):
            self.file = open(self.path)
            print("文件打开....")
            return self
        
        # 离开文件时触发
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("文件关闭")
            # print(exc_type,exc_val,exc_tb)
            self.file.close()  # 关闭文件
            return True
    
    
    with MyOpen('a.txt') as f:
        print(f.file.readline())
    
    # f.file.readline()   # 文件已经关闭了,不能读
    

    11.双下del删除时触发

    __del__ : 
        执行时机:手动删除时立马执行,或者程序运行结束时自动执行
        使用场景:当你的对象使用过程中,打开了不属于解释器的资源;例如,文件,网络端口
    
    class A:
        def __init__(self, name):
            self.name = name
    
        def __del__(self):
            print('删除时触发')
    
        # 删除时关闭
        def __del__(self):
            self.file.close()
    
    jeff = A('jeff')
    del jeff
    # jeff.name  # 已经删除,无法访问了
    

    12.双下__slots__优化对象内存

    slots:原理,给对象声明只有某些属性,从而删除不必要的内存,不能添加新属性
        1.优化对象内存
        2.限制属性数量
    
    __slots__案例:slots使用
    
    # 第一种:不优化内存
    import sys
    class Person:
        slots = ['name']  # 声明名称空间只有name属性
        def __init__(self, name):
            self.name = name
    p = Person('jeff')
    
    print(sys.getsizeof(p))
    # 结果:56
    
    
    # 第二种:优化内存
    import sys
    class Person:
        __slots__ = ['name']  # 声明名称空间只有name属性
    
        def __init__(self, name):
            self.name = name
    p = Person('jeff')
    print(sys.getsizeof(p))
    #结果:48          #####内存减少了8
    

    单例

    单例:一个对象,多次使用相同的。节约内存空间

    单例模式:
        指的是在确定 "类中的属性与方法" 不变时,需要反复调用该类,
        产生不同的对象,会产生不同的内存地址,造成资源的浪费。
    
        让所有类在实例化时,指向同一个内存地址,称之为单例模式。  ----> 无论产生多个对象,都会指向 单个 实例。
    
        - 单例的优点:
            节省内存空间。
    

    单列模式分类

    单例模式: (面试让你手撸,一定要背下来。)
        1.通过classmethod  类绑定方法
        2.通过装饰器实现
        3.通过__new__实现
        4.通过导入模块时实现
        5.通过元类实现。
    

    1.classmethod类绑定单例

    # 第一种:不用单例
    # 两个不同的对象,地址不一样
    class MySQL():
        def __init__(self, host, port):
            self.host = host
            self.port = port
    
        def singleton(self):
            pass
    
    obj1 = MySQL('192.168.0.101',3306)
    obj2 = MySQL('192.168.0.101',3306)
    print(obj1)
    print(obj2)
    # 结果:
    <__main__.MySQL object at 0x000001FE458A8470>
    <__main__.MySQL object at 0x000001FE458A8518>
    
    
    # 第二种:用单例
    # 一个对象重复使用,指向同一个地址,节约内存
    class MySQL():
        __instance = None  # 标识对象是否已经存在
        def __init__(self, host, port):
            self.host = host
            self.port = port
            
        @classmethod
        def singleton(cls, host, port):  # 单例方法
            if not cls.__instance:
                obj = cls(host,port)
                cls.__instance = obj
            # 如果__instance有值,证明对象已经存在,则直接返回该对象
            return cls.__instance
    
    obj1 = MySQL.singleton('192.168.0.101',3306)
    obj2 = MySQL.singleton('192.168.0.101',3306)
    print(obj1)
    print(obj2)
    # 结果:
    <__main__.MySQL object at 0x000001D2B79D8518>
    <__main__.MySQL object at 0x000001D2B79D8518>
    

    2.双下new方法单例

    class Singleton(object):
        def __new__(cls, *args, **kwargs):
            if not hasattr(cls, '_instance'):
                res = super(Singleton, cls)
                cls._instance = res.__new__(cls, *args, **kwargs)
            return cls._instance
    
    class A(Singleton):
        pass
    
    obj1 = A()
    obj2 = A()
    print(obj1)
    print(obj2)
    # 结果:
    <__main__.A object at 0x000001F81A3B8518>
    <__main__.A object at 0x000001F81A3B8518>
    
  • 相关阅读:
    常见寻找OEP脱壳的方法
    Windows内核原理系列01
    HDU 1025 Constructing Roads In JGShining's Kingdom
    HDU 1024 Max Sum Plus Plus
    HDU 1003 Max Sum
    HDU 1019 Least Common Multiple
    HDU 1018 Big Number
    HDU 1014 Uniform Generator
    HDU 1012 u Calculate e
    HDU 1005 Number Sequence
  • 原文地址:https://www.cnblogs.com/WQ577098649/p/11947049.html
Copyright © 2020-2023  润新知