Python面向对象06 /元类type、反射、函数与类的区别、特殊的双下方法

目录

  • Python面向对象06 /元类type、反射、函数与类的区别、特殊的双下方法
  • 1. 元类type
  • 2. 反射
  • 3. 函数与类的区别
  • 4. 特殊的双下方法

1. 元类type

  • type:获取对象从属的类
    Python中一切皆对象,类在某种意义上也是一个对象
    Python中自己定义的类,以及大部分内置类,都是由type元类(构建类)实例化得来的
# type 获取对象从属于的类
print(type(A))
print(type(str))
print(type(dict))
  • type与object的关系:
    object类是type类的一个实例 print(type(object))
    object类是type类的父类 print(issubclass(type,object))

2. 反射

  • 定义:通过字符串操作对象的方式,程序对自己内部代码的一种自省方式
  • 内置函数:hasattr getattr setattr delattr (attr 是属性的意思)
  • 反射可以作用的对象:实例对象,类,本模块,其他模块
    从对象角度应用反射
class A:
    country = '中国'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def func(self):
        print('in A func')
obj = A('张三',66)

# hasattr: 判断有无属性
print(hasattr(obj,'name'))
print(hasattr(obj,'country'))   # 报错
print(hasattr(obj,'func'))   # 报错

# getattr: 获取属性
if hasattr(obj,'name'):
    getattr(obj,'name')
    
# setattr: 设置属性/delattr: 删除属性
setattr(obj,'sex','男')
delattr(obj,'name')

从类的角度应用反射

class A:
    country = '中国'
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def func(self):
        print(self)
        print('in A func')

if hasattr(A,'func'):
    obj = A('张三', 26)
    getattr(obj,'func')()
    getattr(A,'func')(obj)

从其他模块应用反射

import tbjx

# 1. 找到tbjx对象的C类,实例化一个对象.
obj = getattr(tbjx,'C')('123')

# 2. 找到tbjx对象的C类,通过对C类这个对象使用反射取到area.
print(getattr(tbjx.C,'area'))

# 3. 找到tbjx对象的C类,实例化一个对象,对对象进行反射取值.
obj = getattr(tbjx,'C')('张三')
print(obj.name)
print(getattr(obj,'name'))

从当前模块应用反射

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__])
getattr(sys.modules[__name__],'func1')()
getattr(sys.modules[__name__],'func2')()
getattr(sys.modules[__name__],'func3')()

# 本模块的模块名:sys.modules[__name__]
  • 反射应用示例:
class User:
    def login(self):
        print('欢迎来到登录页面')

    def register(self):
        print('欢迎来到注册页面')

    def save(self):
        print('欢迎来到存储页面')

choose_dic = {
    1: User.login,
    2: User.register,
    3: User.save,
}

while 1:
    choose = input('请输入序号: \n1: 登录\n2: 注册\n3: 存储').strip()
    obj = User()
    choose_dic[int(choose)](obj)

3. 函数与类的区别

  • 函数都是显性传参,方法都是隐形传参
class A:
    @classmethod
    def func(cls,a):
        pass
    @staticmethod
    def func1():
        pass

A.func(666)
A.func()
  • 通过打印函数名的方式,区别什么是方法,什么是函数
def func1():
    pass
class A:
    def func(self):
        pass
print(func1)
print(A.func)
obj = A()
print(obj.func)

# 结果:
<function func1 at 0x000000A9C59C1EA0>
<function A.func at 0x000000A9C75DE268>
<bound method A.func of <__main__.A object at 0x000000A9C744D4A8>>
  • 可以借助模块判断类中的是方法还是函数
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(A.func,FunctionType))  # True
print(isinstance(obj.func,FunctionType))  # False
print(isinstance(obj.func,MethodType))  # True

4. 特殊的双下方法

  • 特殊的双下方法: 原本是开发python这个语言的程序员用的.源码中使用的,双下方法: 你不知道你干了什么就触发某个双下方法
# 1.__len__   len(b)执行b类从属父类的__len__方法,必须要有return int(返回值)
class B:
    def __init__(self,name,age):
        self.name = name
        self.age =age
    def __len__(self):
        return len(self.__dict__)  # 2
b = B('张三',28)
print(len(b))


# 2.__hash__  hash()触发__hash__双下方法
class A(object):
    def __hash__(self):
        return 123456
obj = A()
print(hash(obj))


# 3.__str__ 里边必须有return "字符串"类型  (优先级高于__repr__)
#   -  打印对象的时候,会触发__str__方法
#   -  str转化也可以触发
class A:
    def __init__(self,name,age):
        self.name = name
        self.age =age
    def __str__(self):
        print('触发str方法')
        return f'姓名: {self.name} 年龄: {self.age}'
a = A('张三',35)

# 打印对象触发__str__方法
print(f'{a.name}  {a.age}')
print(a)

# 直接str转化也可以触发.
print(str(a))



# 4.__repr__  里边必须有return "字符串"类型
#   -  打印对象的时候,会触发__repr__方法
class A:
    def __init__(self,name,age):
        self.name = name
        self.age =age
    def __repr__(self):
        print(666)
        return f'姓名: {self.name} 年龄: {self.age}'

a = A('张三',35)
print(a)
print(repr(a))


# 5.__call__  对象()触发对象从属类(父类)的__call__方法
class Foo:
    def __init__(self):
        pass
    def __call__(self, *args, **kwargs):
        print('__call__')
obj = Foo()
obj()


# 6.__eq__   两对象==时触发,return True/false(可以返回数字,字符串 一般返回布尔值)
class A(object):
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        print('__eq__')
        return True
x = A()
y = A()
print(x == y)


# 7.__del__ 析构方法 回收对象时触发__del__方法
class A:
    def __del__(self):
        print('__del__')
obj = A()
del obj


# 8.__new__  new一个对象(构造方法),实例化对象的时候会触发,对象是object类的__new__方法,产生了一个对象
class A(object):
    def __init__(self):
        print('in init function')

    def __new__(cls, *args, **kwargs):
        print('in new function')
        return object.__new__(A)

# 对象是object类的__new__方法 产生了一个对象.
a = A()

# 类名()
# 1. 先触发 object的__new__方法,此方法在内存中开辟一个对象空间.
# 2. 执行__init__方法,给对象封装属性.

# def __init__(self):(不能写返回值,因为__new__已经有返回值了,不能同时接收两个返回值,只能接收__new__的返回值)
    


# 9.__item__系列(4个)
# __getitem__ __setitem___ __delitem__ 对对象做类似于字典的(增删改查)触发__item__系列
class Foo:
    def __init__(self,name):
        self.name=name
def __getitem__(self, item):
    # print(item)
    # print(666)
    return self.__dict__[item]

def __setitem__(self, key, value):
    # self.__dict__[key]=value
    print(key)
    print(value)

def __delitem__(self, key):
    print('del obj[key]时,我执行')

f1=Foo('zhangsan')
f1['age']
f1[1] = 2
del f1[1]


# 10.__enter__ __exit__  with 上下文管理(2个)
class A:

    def __init__(self, text):
        self.text = text

    def __enter__(self):  # 开启上下文管理器对象时触发此方法
        self.text = self.text + '您来啦'  # 第一步
        print(11111)
        return self  # 必须!!!将实例化的对象返回f1

    def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法
        print(333)  # 第三步
        self.text = self.text + ',这就走啦'

with A('大爷') as f1:
    print(2222)
    print(f1.text)  # 第二步
print(f1.text)  # 第四步



# 11.__iter__  for循环会触发此方法
class A:
    def __init__(self,name):
        self.name = name

    def __iter__(self):
        for i in range(10):
            yield i

obj = A('张三')
for i in obj:
    print(i)

# 12.__getattr__(self,item),__setattr__(self,key,value),__delattr__ 
#   obj.属性会触发__getattr__(self,item)方法
#   obj.属性=123 会触发__setattr__(self,key,value)   
#   del obj.属性 就会触发__delattr__ 此方法