python 26 反射

1. 类的反射

程序对自己内部代码的一种自省方式。
定义:通过字符串取操作对象的方式。
可应用于实例对象、类、本模块、其他模块。 带有点 . 的方式都可用反射方法。
四种方法:
    1. hasattr(object, name)  # 判断、检测
    2. getattr(object, name)  # 获取
    3. setattr(object, name)  # 设置
    4. delattr(object, name)  # 删除属性

1.1 实例对象

class A:
    country = '中国'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def func(self):
        print('in A func')

obj = A("meet", 18)

print(hasattr(obj, 'name')) # True 检测是否有name属性
print(hasattr(obj, 'sex'))  # False 

print(getattr(obj, 'name')) # 获取obj的name属性
print(getattr(obj, 'sex', None))      
    #指定获取不到,返回None
getattr(obj,'func')()    
    # 调用obj的func方法,自动将obj地址传入参数中
if hasattr(obj, 'func'):
    getattr(obj, 'func')()
    
setattr(obj, 'sex', '男')  # 给obj增加 sex='男' 属性
deltattr(obj,'name')    # 删除obj的name属性
print(obj.__dict__)

1.2 类

# 通过类名
class A:
    country = '中国'

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def func(self):
        print('in A func')
        
if hasattr(A, 'country')
    print(getattr(A, 'country'))  # 中国

if hasattr(A, 'func'):
    obj = A("meet", 18)
    getattr(A, 'func')(obj)
#或:getattr(obj,'func')()

1.3 其他模块 -- 其他.py文件

# 名字为 tbjx.py 的文件

name = "太白金星"

def func():
    print("这是func函数")

class C:
    area = '北京'

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

    def func1(self):
        print('in C func1')
# 本文件
import tbjx    # 导入

print(getattr(tbjx,'name'))  # 获取变量name
getattr(tbjx, 'func')()     # 执行func函数

obj = getattr(tbjx,'C')('meet') # 实例化对象

print(getattr(tbjx.C, 'area'))  # 查找C类的area属性

ret = getattr(tbjx,'C') # 实例化对象后执行类的func1方法
obj = ret('meet')
getattr(obj, 'func')()

1.4 本模块 -- 当前.py文件

import sys
sys.modules[__name__]  # 获取当前py文件的模块对象
def func1():
    print('in func1')

def func2():
    print('in func2')

def func3():
    print('in func3')

def func4():
    print('in func4')

import sys
content = input('请输入:')    # 输入函数名
ret = sys.modules[__name__]  # 获取本文件模块的对象
getattr(ret, content)()
class User:
    user_list = [('login', '登录'), ('register', '注册'), ('save', '存储')]

    def login(self):
        print('欢迎来到登录页面')

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

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

while True:
    obj = User()
    for i in enumerate(obj.user_list, 1):
        print(f'{i[0]}.{i[1][1]}')
    choose = input('请输入序号:').strip()
    getattr(obj, obj.user_list[int(choose)-1][0])()

2. 函数与方法的区别

2.1区别的方法:

方法一:
    通过打印函数名的方式。 通过类名调用的方法是函数,通过对象调用类中的实例方法,是方法。
方法二:借助模块
    from types import FunctionType
    from types import MethodType
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

2.2 总结

总结:
    函数都是显性传参,方法都是隐形传参;
    类方法是一个方法,静态方法是一个函数。
扩展:Java中只有方法,C中只有函数,C++么,则取决于是否在类中。

3. 特殊的双下方法

​ 原本是开发python这个语言的程序员用的,源码中使用的。不能轻易使用、使用。

3.01 __len__ (len一下对象就触发)

class B:
    def __len__(self):
        print(666)

b = B()
len(b)      # len 一个对象就会触发 __len__方法。

# 返回a对象的属性的个数
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))

3.02 __hash__ (hash一下对象就触发)

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))   # 若本类没有,就会从object父类找

3.03 __str__ (打印对象触发、str()也会触发)

class A:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def __str__(self):
        return f'姓名:{self.name} 年龄:{self.age}'
    # 必须是 return 字符串
a = A('meet', 18)
print(a)    # 触发  

3.04 __repr__ (打印对象和repr()都会触发)

class A:
    def __init__(self):
        pass
    def __repr__(self):
        return '太白'
a = A()
print(repr(a))
print('%r'%a)    # 优先级低于str

3.05 __call__ (对象名(),触发)

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print('__call__')


obj = Foo() # 执行 __init__
obj()       # 执行 __call__

3.06 __eq__ (打印对象触发)

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)   # 触发

3.07 __del__ (析构方法)

析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

3.08 __new__ (构造方法 类名()触发)

class A:
    def __init__(self):
        self.x = 1
        print('in init function')
    def __new__(cls, *args, **kwargs):
        print('in new function')
        return object.__new__(A, *args, **kwargs)

a = A()     #触发
print(a.x)

# 类名(),触发object类的__new__方法,产生了一个对象空间并返回到  类名(), 再触发__init__方法,封装对象属性。

单例模式:

一个类只允许实例化一个对象。 将对象唯一化(延用同一个对象空间)。
方便对实例个数的控制并节约系统空间。  如:电脑的任务管理器。
class A:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            obj = object.__new__(cls)
            cls.__instance = obj
        return cls.__instance
obj = A()
print(obj)
obj1 = A()
print(obj1)   # 两次地址相同

猜你喜欢

转载自www.cnblogs.com/yzm1017/p/11333007.html