zoukankan      html  css  js  c++  java
  • python学习之面向对象(四)

    6.9 反射

    反射是非常重要的内置函数之一。

    反射是通过字符串去操作对象相关的属性,这里的对象包括:实列,类,当前模块,其他模块。

    主要的四个函数:

    查看: hasattr(对象,待查内容的字符串形式) 判断有没有,返回True或者False

    获取: getattr(对象,要获取的内容的字符串形式,获取不到时的返回值)

    增加: setattr(对象,要增加的内容的字符串形式)

    删除: delattr(对象,要'删除的内容的字符串形式)

    6.9.1 实例化中使用

    class LOL:
        place = '召唤师峡谷'
        def __init__(self,name,role):
            self.name = name
            self.role = role
        def equip(self):
            print('装备什么')
            
    gailun = LOL('盖伦','战士')
    print(gailun.name)
    
    print(hasattr(gailun,'name'))
    print(getattr(gailun,'name'))
    print(getattr(gailun,'team','没有此属性'))
    
    setattr(gailun,'team','德玛西亚')
    print(getattr(gailun,'team','没有此属性'))
    print(gailun.__dict__)
    
    delattr(gailun,'team')
    print(getattr(gailun,'team','没有此属性'))
    
    # 通过hasattr判断,通过getattr获取,来操作对象的属性和方法
    if hasattr(gailun,'equip'):   #判断对象里面有没有
        print(getattr(gailun,'equip'))  #若果有,看拿到的是什么
        getattr(gailun,'equip')()   #操作对象的方法
    

    6.9.2 类中使用

    class LOL:
        place = '召唤师峡谷'
        def __init__(self,name,role):
            self.name = name
            self.role = role
    
        def equip(self):
            print(self)
            print('装备什么')
    
    gailun = LOL('盖伦','战士')
    
    print(hasattr(LOL,'place'))
    print(hasattr(LOL,'equip'))
    getattr(LOL,'equip')(gailun)
    

    6.9.3 当前脚本中使用

    class LOL:
        place = '召唤师峡谷'
        def __init__(self,name,role):
            self.name = name
            self.role = role
    
        def equip(self):
            print(self)
            print('装备可以加强属性')
    
    def func1():
        print('in func1')
    def func2():
        print('in func2')
    def func3():
        print('in func3')
    
    # 获取当前脚本并把它赋值给一个变量
    import sys
    this_module = sys.modules[__name__]  #当前脚本这个对象
    if hasattr(this_module,'func1'):
    	getattr(this_module,'func1')()
    
    cla = getattr(this_module,'LOL')   #可以获取当前脚本中的类
    cla.equip(cla)      
    nvjing = cla('凯特琳','射手')
    print(cla)
    print(nvjing)
    print(nvjing.__dict__)
    
    # 将以上函数的函数名的字符串形式放到列表中
    l = [f"func{i}" for i in range(1,4)]
    for item in l:      # 利用getattr运行l列中的函数
        getattr(this_module,item)(
    

    6.9.4 其他模块中使用

    在另一个py文件中,设置

    # 反射2.py
    def fun1():
        print('in fen1')
    aa = 'aa'
    

    在本文件中调用反射2.py中的函数

    import 反射2 as other
    getattr(other,'fun1')()
    

    6.9.5 场景使用

    class Auth:
    
        def login(self):
            print('登录函数')
    
        def register(self):
            print('注册函数')
    
        def exit(self):
            print('退出...')
    
    obj = Auth()
    while 1:
        func_name = input('请输入选择:').strip()
        if hasattr(Auth,func_name):
            getattr(Auth,func_name)(obj)
    

    6.10 函数与方法的判断

    该节旨在体验双下发放的触发情况,所以使用print和return来帮助提示相关方法的执行

    通过名称

    通过名称可以大致判断

    def func1():
        pass
    
    class A:
        def func(self):
            pass
    
    print(func1)
    obj = A()
    print(obj.func)
    # 输出信息中含有function的就是函数
    # 输出的信息中含有bound method的就是方法
    

    通过type模块验证

    from types import FunctionType
    from types import MethodType
    
    def func():
        pass
    class A:
        def func(self):
            pass
    obj = A()
    print(isinstance(func,FunctionType))       #True
    print(isinstance(func,MethodType))         #False
    print(isinstance(A.func,FunctionType))     #True   func在类中是函数
    print(isinstance(obj.func,FunctionType))   #Flase
    print(isinstance(obj.func,MethodType))     #True  func在对象中是方法
    

    定义在类中的共有函数,在类中是函数,在对象中是方法

    类的静态方法是函数

    类方法是一种方法,静态方法是一种函数

    对于写在类内部的静态方法实际上是函数,而类方法就是一种方法

    from types import FunctionType
    from types import MethodType
    
    class A:
    
    
        @classmethod
        def func1(cls):
            pass
    
        @staticmethod
        def func2(self):
            pass
    obj = A()
    
    print(isinstance(A.func1,FunctionType))       #False
    print(isinstance(A.func1,MethodType))         #True
    print(isinstance(obj.func1,FunctionType))     #False
    print(isinstance(obj.func1,MethodType))       #True
    print(isinstance(A.func2,FunctionType))       #True
    print(isinstance(A.func2,MethodType))         #False
    print(isinstance(obj.func2,FunctionType))     #True
    print(isinstance(obj.func2,MethodType))       #False
    

    函数与方法的区别

    函数是显式传递数据,俗话说,函数一般需要传参
    函数与对象无关

    方法中的数据是隐式传递数据
    方法可以操作类内部的数据
    方法是跟对象相关的

    6.11 双下方法

    双下方法主要是针对开发python语言的设计使用的,要慎用。

    双下方法是具有特殊意义的方法,其执行方式也比较特殊,不同的双下方法有不同的触发方式。

    __len__方法

    一个对象之所以能够使用len()函数,根本原因是该对象的父类中含有__len__函数,在使用len()时,类中的__len__函数就会执行,并返回一个int值给调用者。

    class A:
        def __len__(self):
            print('aaa')
            return 1
    
    obj =  A()
    print(len(obj))
    

    __hash__方法

    能够使用hash()函数的对象的父类内含有__hash__函数,并由hash()触发

    class A:
        aa = 'aa'
        def __hash__(self):
            print('正在执行hash函数')
            return 1
    obj = A()
    print(hash(obj))
    

    __repr__方法

    如果类中定义了__repr__函数,repr对象时,默认输出该函数的返回值

    class A:
        def __init__(self):
            pass
        def __repr__(self):
            return '输出__repr__的返回值'
    
    obj = A()
    print(repr(obj))
    print('%r' %obj)
    

    __str__方法**

    如果类中定义了__str__函数,print对象时,默认输出该函数的返回值

    class A:
        def __init__(self):
            pass
        def __str__(self):
            return '输出__str__的返回值'
    
    obj = A()
    print(obj)
    print('%s' %obj)
    

    __call__方法**

    如果类中定义了__call__函数,实例化对象后,对象()或者A()()就能触发该函数

    class A:
        def __call__(self):
            print('可以返回很多的内容,形式多样')
    obj = A()
    print(obj())
    A()()
    

    __del__方法**

    析构方法,当对象在内存中被释放时,自动触发执行。

    python本身具有垃圾回收机制,大多数情况下我们不必要去关心内存的分配与释放,该函数略显鸡肋

    class A:
        def __del__(self):
            print('清空内存')
    obj = A()
    del obj
    如果该程序运行结束,即使没有使用del也会触发__del__
    

    __eq__方法

    进行 == 比较时,就会触发该方法

    class A:
        def __init__(self):
    
            self.aa = 11
            self.bb = 22
        def __eq__(self,obj):
            if self.aa == obj.aa and self.bb == obj.bb:
                print('正在执行__eq__')
    obj1 = A()
    obj2 = A()
    print(obj1 == obj2)
    
    class A:
        def __init__(self):
    
            self.aa = 11
            self.bb = 22
        def __eq__(self,obj):
            if self.aa == obj.aa and self.bb == obj.bb:
                print('正在执行__eq__')
    class B(A):
        pass
    
    obj1 = A()
    obj2 = B()
    print(obj1 == obj2)
    

    __new__方法**

    __new__真正的创建并返回一个对象的方法。实例化对象时,其实首先执行的是__new__创建内存空间

    class A:
        def __init__(self):
            self.aa = 1
            print('创建了对象')
    
        def __new__(cls, *args, **kwargs):  #第二步:执行__new__,这里测试使用,没有创建对象空间的作用
            ret = super().__new__(cls, *args, **kwargs)   #执行一下父类的__new__创建对象使用,
            print('执行__new__对象')
            return ret
    
    obj = A()   #第一步,类名()
    s = obj.aa
    print(obj)
    

    类名()触发__new__并将类名自动传给cls

    单例模式(设计模式)***

    一个类只能实例化一个对象,无论实例化多少次,内存中都只有一个改类的对象

    单例模式设计

    class A:
        __instance = None  #对象空间
    
        def __new__(cls, *args, **kwargs):
            if not cls.__instance :  #如果没有创建过对象
                ret = super().__new__(cls, *args, **kwargs)   #创建一个对象
                cls.__instance = ret
            return cls.__instance
    
    obj = A()
    print(obj)
    obj1 = A()
    print(obj1)
    

    单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
    【采用单例模式动机、原因】
    对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
    如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
    【单例模式优缺点】
    【优点】
    一、实例控制
    单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
    二、灵活性
    因为类控制了实例化过程,所以类可以灵活更改实例化过程。
    【缺点】
    一、开销
    虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
    二、可能的开发混淆
    使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
    三、对象生存期
    不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用

    __item__系列

    当对实例化的对象进行类似于字典的操作时,会触发__item__系列对应的方法

    class LOL:
        def __init__(self,name):
            self.name = name
    
        def __getitem__(self, item):
            print(self.__dict__[item])
            print('在使用字典的方式查看属性时,getitem执行')
    
        def __setitem__(self, key, value):
            self.__dict__[key] = value
            print('在使用字典的方式添加属性时,setitem执行')
    
        def __delitem__(self, key):
            print('del obj[key]时,delitem执行')
            self.__dict__.pop(key)
    
        def __delattr__(self, item):
            print('del obj.key时,我执行')
            self.__dict__.pop(item)
    
    gailun = LOL('盖伦')
    gailun['age'] = 18
    print(gailun.__dict__['age'])
    print(gailun.age)
    del gailun['age']
    del gailun.age
    print(gailun.__dict__['age'])
    

    难点

    class StarkConfig:
        def __init__(self,num):
            self.num = num
    
        def run(self):
            self()
    
        def __call__(self, *args, **kwargs):
            print(self.num)
    
    class RoleConfig(StarkConfig):
        def __call__(self, *args, **kwargs):
            print(1234567)
    
        def __getitem__(self, item):
            return self.num[item]
    
    v1 = StarkConfig('sam')
    v2 = RoleConfig('john')
    v1.run()
    

    上下文管理器相关

    __enter__ __exit__这两个方法能够把对象像文件一样进行操作

    # 如果没有这两个函数时,不能进行 with as 操作
    class A:
        def __init__(self,txt):
            self.txt = txt
            
    with A('盖伦') as f1:
        print(f1.txt)
    
    class LOL:
        def __init__(self,name):
            self.name = name
    
        def __enter__(self):
            self.name  = '召唤' + self.name
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.name = self.name + '进行战斗'
            return self
    
    with LOL('盖伦') as f1:
        print(f1.name)  #召唤盖伦
    print(f1.name)  #召唤盖伦进行战斗
    

    应用到文件中

    class Opperation:
        def __init__(self,name,mode):
            self.name = name
            self.mode = mode
    
        def __enter__(self):
            print('这里是入口')
            self.file = open(self.name,self.mode)
            return self.file
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.file.close()
            print('已关闭')
    
    with Opperation('test.py','r') as f:    
        for item in f:
            print(item)
            
    打开文件前显示  ----  这里是入口
    文件关闭时显示  ----  已关闭
    

    练习

    class UserInfo:
        pass
    class Department:
        pass
    
    class StarkConfig:
        def __init__(self,num):
            self.num = num
    
        def change(self,request):
            print(self.num,request)
    
        def run(self):
            self.change(999)
    
    class RoleConfig(StarkConfig):
        def change(self,request):
            print(666,self.num)
    
    class AdminSite:
       def __init__(self):
           self._registry = {}
    
       def register(self,k,v):
           self._registry[k] = v(k)
    
    site = AdminSite()
    site.register(UserInfo,StarkConfig)
    site.register(Department,RoleConfig)
    
    for k,v in site._registry.items():
        v.run()
    
    class StarkConfig:
        def __init__(self,num):
            self.num = num
    
        def run(self):
            self()
    
        def __call__(self, *args, **kwargs):
            print(self.num)
    
    class RoleConfig(StarkConfig):
        def __call__(self, *args, **kwargs):
            print(1234567)
    
        def __getitem__(self, item):
            return self.num[item]
    
    v1 = StarkConfig('sam')
    v2 = RoleConfig('john')
    v1.run()
    

    class A:
        list_display = []
    
        def get_list(self):
            self.list_display.insert(0,33)
            return self.list_display
    s = A()
    print(s.get_list())  # [33]
    
    class A:
        list_display = [1,2,3]
        def __init__(self):
            self.list_display = []
        def get_list(self):
            self.list_display.insert(0,33)
            return self.list_display
    s = A()
    print(s.get_list())  # [33]
    
    class A:
        list_display = []
        def get_list(self):
            self.list_display.insert(0,33)
            return self.list_display
    class B(A):
        list_display = [11,22]
    
    s = B()
    print(s.get_list())    #[33,11,22]
    

    引用:https://www.cnblogs.com/jin-xin/articles/10325036.html

    仅供参考,欢迎指正
  • 相关阅读:
    tomcat与resin的比较
    Linux Resin 安装配置
    [BZOJ3456]城市规划
    ZJOI 2017 仙人掌
    「LibreOJ NOI Round #1」动态几何问题
    [SDOI2015]约数个数和
    codeforce 940F
    codeforce 940F
    codeforce 940E
    [NOI2009]植物大战僵尸
  • 原文地址:https://www.cnblogs.com/jjzz1234/p/11178724.html
Copyright © 2011-2022 走看看