zoukankan      html  css  js  c++  java
  • 面向对象之 元类 , 反射 , 双下方法

    1.元类 type

    • type元类,又称为构建类,python中一切皆对象,也可以理解为对象,python中自己定义的类,以及大部分内置类,都是由type元类实例化得来的
    元类type
    class A:
        pass
    
    obj = A()
    print(type('abc'))  #<class 'str'>
    print(type([1,2,3]))  #<class 'list'>
    print(type((22,33)))  #<class 'tuple'>
    print(type(A))   #<class 'type'>
    print(type(str))  #<class 'type'>
    print(type(type))   #<class 'type'>
    print(type(object))  #<class 'type'>
    
    • type 与 object 的关系 : object是type类的实例,而type类是object类的子类

      • print(type(object))   #  <class 'type'> 
        object类是type类的一个实例化对象
        
        print(isinstance(type,object))  #True
        结果为真,说明object是type类的实例化对象
        
        print(issubclass(type,object))  #True
        结果为真,说明type类是object类的子孙类
        

    2.反射

    • 定义:程序对自己内部代码的一种自省方式
      • 官方:主要是指程序可以访问检测和修改它本身状态或行为的一种能力/自省
    • python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
    2.1 四种方法,四个方面分析 **一切基于万能的点能够做到的
    hasattr 判断是否存在 True False(万能的点是否成立)
    getattr 判断有就得到结果,没有就报错,可以设置返回值就不报错了
    setattr 添加对象属性
    delattr 删除对象属性
    
    • 实例对象

      class A:
          country = "中国"
      
          def __init__(self,name,age):
              self.name = name
              self.age = age
      
          def func(self):
              print("in A func")
      
      obj = A("alex",22)
      #hasattr 万能的点能调用的都可以用
      print(hasattr(obj,"name"))  #True
      print(hasattr(A,"func"))   #True
      print(hasattr(A,"name"))   #False
      
      print(getattr(obj,"country"))  #中国
      print(getattr(obj,"name"))  #alex
      print(getattr(obj,"func"))  #<bound method A.func of <__main__.A object at 0x000000D16FB1C710>>
      f = getattr(obj,"func")
      f()  #调用func函数
      
      print(getattr(A,"name"))  #报错
      print(getattr(obj,"sex"))  #报错
      print(getattr(A,"name","不存在"))  #不存在
      print(getattr(obj,"sex",None))  #None
      
      print(obj.__dict__)  #{'name': 'alex', 'age': 22}
      setattr(obj,"sex","男")
      print(obj.__dict__)  #{'name': 'alex', 'age': 22, 'sex': '男'}
      
      print(obj.__dict__)  #{'name': 'alex', 'age': 22}
      delattr(obj,"name")
      print(obj.__dict__)  #{'age': 22}
      
      delattr(obj,"country")  #报错 无此属性
      
    • 类 #上边,类名调用的是类的映射 对象调用的是对象的映射

    • 其他模块

      tbjx.py文件中的内容
      
      name = '太白金星'
      
      def func():
          print('in tbjx func')
      
      class C:
          area = '北京'
      
          def __init__(self,name):
              self.name = name
      
          def func(self):
              print('in B func')
      
      1. 找到tbjx对象的C类,实例化一个对象.
      import tbjx
      obj = getattr(tbjx,"C")(tbjx.name)
      
      2. 找到tbjx对象 的C类,通过对C类这个对象使用反射取到area.
      import tbjx
      obj = getattr(tbjx,"C")(tbjx.name)
      print(getattr(obj,"area"))  #北京
      
      3. 找到tbjx对象的C类,实例化一个对象,对对象进行反射取值.
      import tbjx
      obj = getattr(tbjx,"C")(tbjx.name)
      print(getattr(obj,'name')) #太白金星
      
    • 本模块

      a = 666
      def func1():
          print('in func1')
      
      def func2():
          print('in func2')
      
      def func3():
          print('in func3')
      
      def func4():
          print('in func4')
      
      import sys
      print(sys.modules[__name__])  #当前文件模块实例化
      print(getattr(sys.modules[__name__],"a")) #666
      getattr(sys.modules[__name__],"func1")()   #in func1   调用并执行函数
      
      循环上述函数
      lst = [func1,func2,func3,func4]
      for i in lst:
          i()
      
      lst = [f"func{i}" for i in range(1,5)]
      # print(lst)
      for i in lst:
          getattr(sys.modules[__name__],i)()
      

    3.函数与方法的区别 ***函数都是显性传参,方法都是隐性传参.

    from types import FunctionType  函数
    from types import MethodType    对象
    
    python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构建类)实例化得来的.
    python 中一切皆对象, 函数在某种意义上也是一个对象,函数这个对象是从FunctionType这个类实例化出来的.
    python 中一切皆对象, 方法在某种意义上也是一个对象,方法这个对象是从MethodType这个类实例化出来的.
    

    3.1 通过打印函数(方法)名确定

    def func1():
        pass
        
    class A:
        def func(self):
            pass
    print(func1)  #<function func1 at 0x000000EB2BF7DA60>  #函数
    通过类名调用的类中的实例方法叫做函数
    print(A.func)  #<function A.func at 0x000000EB2BF7DAE8> #函数
    通过对象调用的类中的实例方法叫方法
    print(obj.func) #<bound method A.func of <__main__.A object at 0x000000EB2BF7C240>>    #方法
    

    3.2 通过借助模块判断是方法还是函数

    from types import FunctionType
    from types import MethodType
    def func1():
        pass
    
    class A:
        def func(self):
            pass
    
    obj = A()
    print(isinstance(func1,FunctionType))  # True
    print(isinstance(A.func,FunctionType))  # True
    print(isinstance(obj.func,FunctionType))  # False
    print(isinstance(obj.func,MethodType))  # True
    

    3.3函数都是显性传参,方法都是隐性传参.

    class A:
        name = "我不是第一个"
    
        @classmethod
        def func(cls):
            print(cls.name)
    
        @staticmethod
        def func1(argv):
            print(f"{argv}")
    
    obj = A()
    
    A.func()   #隐形传参,第一个参数默认把A传给了cls
    A.func1("显性传参")  #显性传参
    
    obj.func()   #隐形传参,第一个参数默认把A传给了cls
    obj.func1("显性传参") #显性传参
    

    4.双下方法

    特殊的双下方法: 原本是开发python这个语言的程序员用的.源码中使用的.
    

    4.1 __len__ 方法 自定义类中必须要有返回值,且返回值必须是数字(0-正无穷),其他都报错 len()就触发了方法

    class A:
        def __len__(self):
            print(666)
            return 222
    
    a = A()
    print(len(a))  # 666 222
    
    class A:
    
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def __len__(self):
            print(self.__dict__)  #{'name': '太白', 'age': 28}
            return len(self.__dict__)  #内置函数len方法
    
    a = A("太白",28)  #实例化对象
    print(len(a))  # 2
    

    4.2 __hash__ 方法 自定义类中必须要有返回值正负整数都可以,但是-1得到-2

    class A:
        pass
    
    obj = A()
    print(hash(obj))  #触发object类的__hash__方法
    
    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __hash__(self):
            return -1  #唯一不正常的返回结果-2
    
    obj = A()
    print(hash(obj))
    

    4.3 __str__ 方法 自定义类中必须要有返回值且必须是字符串

    class A:
    
        def __init__(self,name,age):
            self.name = name
            self.age =age
    
        def __str__(self):
            return f'姓名: {self.name} 年龄: {self.age}'
    
    a = A("太白",25)
    b = A("宝元",26)
    c = A("日天",27)
    # 打印对象触发__str__方法
    print(a)
    print(b)
    print(c)
    # 直接str转化也可以触发.
    print(str(a))
    

    4.4 _str__ 方法 和_repr__ 方法共同存在时,只执行前者

    class A:
    
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
        def __repr__(self):
            return "我执行不了了"
    
        def __str__(self):
            return "我优先"
    
    a = A("太白",25)
    b = A("宝元",26)
    c = A("日天",27)
    # 打印对象触发__str__方法
    print(a)
    print(b)
    print(c)
    # 直接repr转化也可以触发.
    print(repr(a))
    
    class A:
        __instance = None
    
        def __init__(self,name):
            self.name = name
            #不能设置返回值因为都是类名()调用的
            #不能同时接收多个返回值
    
        def __new__(cls, *args, **kwargs):
            if cls.__instance is None:
                cls.__instance = object.__new__(cls)
                #类名.属性,改变属性
            return cls.__instance
            #返回后猜测还有一个回调机制去调用__init__方法
    
    obj = A("alex")
    print(obj)
    obj1 = A("taibai")
    print(obj1)
    obj2 = A("baoyuan")
    print(obj2)
    print(obj.name)  #baoyuan
    print(obj1.name)  #baoyuan
    print(obj2.name)  #baoyuan
    #三个共用一个内存空间,变量一直在改
    
  • 相关阅读:
    .NET 2.0 WinForm Control DataGridView 编程36计(一)
    Sql Server 日期格式化函数
    FastReport 金额大小写转换自定义函数
    vue.js 三种方式安装(vuecli)
    Android style
    android ui 布局性能优化
    android 手机分辨率
    TCP,IP,HTTP,SOCKET区别和联系
    android2.2 特性
    常见开放api平台OpenAPI
  • 原文地址:https://www.cnblogs.com/lvweihe/p/11330021.html
Copyright © 2011-2022 走看看