面向对象之 元类 , 反射 , 双下方法

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
#三个共用一个内存空间,变量一直在改

猜你喜欢

转载自www.cnblogs.com/lvweihe/p/11330021.html