反射 双下方法
一 : 元类 type
- Type 获取对象从属的类
class A:
pass
print(type('abc')) # <class 'str'>
print(type([1,2,3])) # <class 'list'>
print(type((22,33))) # <class 'tuple'>
-
python 中一切皆对象,类在某种意义上也是一个对象,python 中自己定义的类,以及大部分内置类,都是由 type元类实例化得来的
-
type 与 object 的关系
object 是 type 类的一个实例
object 是type类的父类
print(issubclass(type,object)) # True
二 : 反射
-
程序对自己内部代码的一种自省
-
反射是什么?
通过字符串去操作对象的方式
四种使用场所
实例对象
类
本模块
其他模块
-
hasattr getattr setattr delattr
实例对象
**hasattr : 判断是否存在,存在返回True,不存在返回 False **
print(hasattr(obj,'name')) # True
print(hasattr(obj,'country')) # True
print(hasattr(obj,'func')) # True
getattr : 返回的是具体值,相当于取代那个万能的点
print(getattr(obj,'name')) # 赵海狗
print(getattr(obj,'country')) # 中国
print(getattr(obj,'func')) # <bound method A.func of <__main__.A object at 0x10a3d3b70>>
print(getattr(obj,'func')()) 已经调用了这个函数了
# in A func
# None
print(getattr(obj,'sex',None)) # 指定查不到就返回 None
print(getattr(obj,'sex')) # 报错
setattr : 相当于增加一个属性
setattr(obj,'sex','公') # 增加一个
print(obj.__dict__)
# {'name': '赵海狗', 'age': 78, 'sex': '公'}
**delattr : 删除一个属性 **
delattr(obj,'name') # 删除里面的值
print(obj.__dict__)
{'age': 78, 'sex': '公'}
从类的角度
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,'country'):
# print(getattr(A,'country')) # 中国
if hasattr(A,'func'):
obj = A('赵海狗',26)
getattr(obj,'func')() 在对象中调用,隐性传参
#<__main__.A object at 0x10966c240> 在函数中调用,显性传参 两种是一样的
# in A func
getattr(A,'func')(obj)
# <__main__.A object at 0x10966c240>
# in A func
从其他模块
import tbjx (从其他文件导过来的)
# 1.找到tbjx对象的C类,实例化一个对象
# print(getattr(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')) # 赵海狗
tbjx 文件如下
name = '太白金星'
def func():
print('in tbjx func')
class C:
area = '北京'
def __init__(self,name):
self.name = name
def func(self):
print('in B func')
从当前模块研究反射
a = 666
def func():
print('in 本模块这个对象')
def func1():
print('in func1')
def func2():
print('in func2')
def func3():
print('in func3')
def func4():
print('in func4')
# func1()
# func2()
# func3()
# func4()
import sys
print(sys.modules[__name__])
# <module '__main__' from '/Users/zhl/Desktop/python_24/day26/课堂练习.py'>
# 相当于一个字典 查找都有
print(getattr(sys.modules[__name__],'a'))
# 666
func_lst = [f'func{i}' for i in range(1,5)]
print(func_lst)
for func in func_lst:
getattr(sys.modules[__name__],func)()
in func1
in func2
in func3
in func4
反射的应用
class User:
user_list = [('login','登录'),('register','注册'),('save','存储')]
def login(self):
print('欢迎来到登录界面')
def register(self):
print('欢迎来到注册界面')
def save(self):
print('欢迎来到存储界面')
while 1:
choose = input('请输入序号:\n1:登录\n2:注册\n3:存储\n').strip()
obj = User()
getattr(obj,obj.user_list[int(choose) - 1][0])()
# getattr(obj,'login)
# 这样简化代码 显得更高大上一些
三 : 函数与方法的区别
通过打印函数名的方式区别什么是方法,什么是函数(了解)
def func1():
pass
class A:
def func(self):
pass
print(func1)
print(A.func) # 通过类名调用的类中的实例方法叫做函数
obj = A()
print(obj.func) # 通过对象调用类中的实例方法叫做方法
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
# 所以这个类名调用的类中的实例方法叫做函数
# 通过对象调用类中的实例方法叫做方法
**总结 : **
Python 中一切皆对象,类在某种意义上也是一个对象,Python 中自己定义的类
以及大部分内置类,都是由type 元类实例化而来
Python 中一切皆对象,函数在某种意义上也是一个对象,函数这个对象是从 FunctionType这个实例化出来的
Python 中一切皆对象,方法在某种意义上也是一个对象,方法这个对象是从 MethodType这个类实例化出来的
如何判断类中的是方法还是函数 ? ?
class A:
@classmethod
def func(cls,a): # 显性和隐性是从这里判断
pass
@staticmethod
def func1( ):
pass
A.func(222)
# A.func()
obj = A()
obj.func('是')
# 只要参数不对等,并且有 self cls 就是隐性传参 函数
四 : 特殊的双下方法
用途 : 原本是开发Python这个语言的程序员用的,源码中使用
str : 我们不能轻易使用,慎用
双下方法 : 不知道触发某个方法走下去
__len__
class B:
def __init__(self,name,age):
self.name = name
self.age = age
def __len__(self):
print(self.__dict__)
return len(self.__dict__)
b = B('liye',28) # {'name': 'liye', 'age': 28}
print(len(b)) # 2
print(len({'name':'liye','age':28})) # 2
字典的话就是键值对的个数 其他就是元素的个数
__str__ 用来返回字符串表达式
class A:
def __init__(self,name,age):
self.name = name
self.age = age
def __str__(self):
print(666)
return f'姓名:{self.name} 年龄:{self.age}'
a = A('赵海狗',35)
b = A('李业',33)
c = A('华丽',18)
# 打印对象触发 __str__
print(f'{a.name} {a.age}') # 赵海狗 35
print(f'{b.name} {b.age}') # 李业 33
print(f'{c.name} {c.age}') # 华丽 18
print(a)
#666
# 姓名:赵海狗 年龄:35
print(b)
print(c)
print(str(a)) 直接 str 也可以触发
#666
# 姓名:赵海狗 年龄:35
打印了对象就触发了 str 所以是这个意思
__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)
b = A('李业',12)
c = A('华丽',18)
print(a)
print(repr(a))
# 666
# 姓名:赵海狗 年龄:35
# 666
# 姓名:赵海狗 年龄:35
# 两个结果是一样的
# 打印对象后也是触发 repr 吗? 他两有什么区别呢?和 str
print('我叫%s' % ('alex')) # 我叫alex
print('我叫%r' % ('alex')) # 我叫'alex'
print(repr('fdsaf')) # 'fdsaf'
看这个结果是把字符串啥的引号都给表现出来了
_call_
对象() 自动触发对象从属于类(父类)的__call__方法
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo()
obj()
# __call__
_eq__
class A(object):
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
# return True
x = A()
y = A()
print(x == y)
# True
两种比较
__del__
class A:
def __del__(self):
print(666)
obj = A()
del obj
# 666
_new_
class A(object):
def __init__(self):
self.x = 1
print('in init function')
def __new__(cls, *args, **kwargs):
print('in new function')
return object.__new__(A) # object 342534
# # 对象是object类的__new__方法 产生了一个对象.
a = A()
#in new function
in init function
# 类名()
# 1. 先触发 object的__new__方法,此方法在内存中开辟一个对象空间.
# 2. 执行__init__方法,给对象封装属性.
我自己的理解是先执行 new 然后再执行 init
五 : python 中单例模式 重要必须会默写
class A:
__instance = None
def __init__(self,name):
self.name = name
def __new__(cls,*args,**kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance
obj = A('alex')
print(obj)
obj1 = A('李业')
print(obj1.name)
print(obj.name)
# <__main__.A object at 0x106e8cf28>
# 李业
# 李业