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) # 两次地址相同