zoukankan      html  css  js  c++  java
  • 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>
    
  • 相关阅读:
    Linux用户行为日志审计
    日志分析-Web
    secedit.exe 本地审核
    StreamCQL
    一个关于缓存很好的文章~
    Java免费开源数据库、Java嵌入式数据库、Java内存数据库
    MySQL db优化
    威胁情报
    《javascript设计模式》读书笔记二(封装和隐藏信息)
    Mysql触发器
  • 原文地址:https://www.cnblogs.com/WQ577098649/p/11947049.html
Copyright © 2011-2022 走看看