【知识点】
1、isinstance() 判断对象所属类型,包含继承关系
type()与isinstance()的区别
1 classmystr(str):pass2 ms=mystr('alex')3 print(ms)4 print(type(ms) isstr) # 不包含继承关系,只管一层5 print(isinstance(ms,str)) # 包含所有的继承关系
2、issubclass(B,A) 判断B是不是A的子类(判断类与类之间的继承关系)
3、反射:用字符串数据类型的变量名来访问这个变量的值
方法:getattr hasattr setattr delattr
(1)在类的应用:静态属性(静态字段)、类方法、静态方法
命名空间.XXX=getattr(命名空间,'XXX') 属性直接用,方法在后加()
1 classStudent:2 ROLE='STUDENT'
3
4 @classmethod5 def check_course(cls):6 print("查看课程了")7
8 @staticmethod9 def login():10 print("登录")11 # 反射查看属性12 print(Student.ROLE) # 通过类名调用13 print(getattr(Student,'ROLE'))14
15 # 反射调用方法16 getattr(Student,'check_course')() # 查看课程了 # 类方法17 getattr(Student,'login')() # 登录 # 静态方法18
19 num=input("请输入要调用的方法>>>")20 ifhasattr(Student,num): # 如果输入的num是Student这个命名空间里的方法,则返回True,否则返回Flase21 getattr(Student,num)()22 else:23 num = input("你输入的有误,请重新输入要调用的方法>>>")
(2)在对象中应用:
1 # 在对象中2 classA():3 def __init__(self,name):4 self.name=name5
6 def func(self):7 print("in func")8
9 a=A('123')10 print(a.name) # 123
11 print(getattr(a,'name')) # 123
12 getattr(a,'func')() # in func
(3)在模块中
1 # 在模块2 import os3 '''4 # os.rename('__init__.py','init')5 # getattr(os,'rename')('init','__init__.py')6 rename=os.rename7 rename2=getattr(os,'rename')8 rename('__init__.py','init') # os.rename('__init__.py','init')9 rename2('init','__init__.py') # getattr(os,'rename')('init','__init__.py')10 '''11 # 反射自己模块中的内容,找到自己当前文件所在的命名空间12 def wahaha():13 print("wahaha")14
15 def qqxing():16 print("qqxing")17
18 # wahaha()19 # qqxing()20
21 import sys22 # print(sys.modules)23 # sys.modules 这个方法,表示所有在当前这个python程序中导入的模块24 # print(sys.modules['__main__'])25 my_file=sys.modules['__main__'] # 当前文件所在模块26 # my_file.wahaha()27
28 getattr(my_file,'wahaha')() # wahaha
【反射总结】
hasattr getattr
① 类名.名字
getattr(类名,'名字')
② 对象名.名字
getattr(对象,'名字')
③ 模块名.名字
import 模块
getattr(模块,'名字')
④ 自己文件.名字
import sys
getattr(sys.modules['__main__'],'名字')
【反射的应用】
1 # 一个选课查询系统2 classManager():3 OPERATE_DIC=[4 ('create_student','创建学生账号'),5 ('create_course','创建学生课程'),6 ('check_student','查看学生信息')7 ]8
9 def __init__(self,name):10 self.name=name11
12 def create_student(self):13 print("创建学生账号")14
15 def create_course(self):16 print("创建学生课程")17
18 def check_student(self):19 print("查看学生信息")20
21
22 classStudent():23 OPERATE_DIC =[24 ('choose_course', '学生选择课程'),25 ('check_course', '学生查询课程')26 ]27
28 def __init__(self,name):29 self.name=name30
31 def choose_course(self):32 print("学生选择课程")33
34 def check_course(self):35 print("学生查询课程")36
37
38 def login():39 count=1
40 while count<4:41 username=input("请输入用户名:")42 password=input("请输入密码:")43 with open('userinfo',mode='r',encoding='utf-8') asf:44 for line inf:45 user,pwd,ident=line.strip().split('|')46 if username == user and password ==pwd:47 print("登录成功")48 returnusername,ident49 else:50 print("输入错误,请重新输入,你还有%d次机会" % (3-count))51 break
52 count+=1
53
54 import sys55 def main():56 whileTrue:57 user,id=login()58 file=sys.modules['__main__'] # 拿到自己当前所在的模块59 cls=getattr(file,id) # id=manager,student 所以可以拿到相应的类60 obj=cls(user) # 类的实例化,并传入参数61 lst=getattr(cls,'OPERATE_DIC') # 通过类拿到静态属性值62 for num,el in enumerate(lst,1): # enumerate()是将列表中元素添加上序号,从1开始则需要添加起始参数163 print(num,el[1]) # num是序号,el是元组 el[1]获取元组的第二个参数64 i=int(input('请输入要选择项序号:'))65 getattr(obj,lst[i-1][0]) () # lst[i-1][0]得到的是字符串,故用getattr()方法66 main()
4、内置函数
__名字__
# 类中的特殊方法\内置方法
#双下方法
#魔术方法
类中的每一个双下方法都有它自己的特殊意义
(1)__call__ 方法
对象() 相当于调用__call__方法
类名()() 相当于先实例化一个对象,再对对象()。与上面结果一样
1 # __call__2 classA:3 def __call__(self,*args,**kwargs):4 print("执行call方法了")5
6 classB:7 def __init__(self,cls):8 print("在实例化A之前做一些事")9 self.a=cls()10 self.a()11 print("在实例化A之后做一些事")12 # a=A()13 # a() # 相当于调用__call__方法14 #A()() # 和上面结果一样,相当于调用__call__15 B(A)
(2)__len__方法
len(obj) 相当于调用了这个obj的__len__方法
__len__方法return的值就是len函数返回的值
#如果一个obj对象没有__len__方法,那么len函数就会报错
1 # __len__方法2 #内置函数与类的内置方法是有奸情的3 classMylist:4 def __init__(self):5 self.lst=[1,2,3,4,5,6]6 self.name='123'
7 self.age=45
8
9 def __len__(self):10 print("执行__len__方法了")11 returnlen(self.__dict__)12 m=Mylist()13 print(len(m)) # 执行__len__方法了 3
(3)__new__方法(构造方法)
在执行__init__之前,开辟一个空间。
1 # __new__构造方法2 classSingle:3 def __new__(cls,*args,**kwargs):4 obj=object.__new__(cls)5 print("在new方法里",obj)6 returnobj7
8 def __init__(self):9 print("在init方法里",self)10 #1、开辟一个空间,属于对象的11 #2、把这个对象的空间传给self,执行init12 #3、将这个对象的空间返回给调用者13 obj=Single() #结果:在new方法里 <__main__.single object at>
14 #结果:在init方法里 <__main__.single object at>
15 #若是类中没有__nem__方法,则会调用object里的__new__来开辟空间
【一道面试题】
写出一个单例类?
#1、单例:如果一个类,从头到尾只能有一个实例(说明从头到尾只开辟了一块属于对象的空间),那么这个类就是一个单例类。
单例的例子代码:
1 # 写一个单例类2 classSingle:3 __ISINSTANCE=None4 def __new__(cls,*args,**kwargs):5 ifnot cls.__ISINSTANCE:6 cls.__ISINSTANCE=object.__new__(cls)7 returncls.__ISINSTANCE8
9 def __init__(self,name,age):10 self.name=name11 self.age=age12
13 s1=Single('太白',23)14 s2=Single('Alex',26)15 print(s1.name) # Alex16 print(s2.name) # Alex17 # 原因:首先开辟一个空间,并且只有一个空间。最开始将name赋值“太白”,age赋值23,18 # 然后执行S2=Single('Alex',26),由于只有一个空间,故将此前的值覆盖掉,所以最后打印都是“Alex”
注意:上述例子首先开辟了一个空间,并且只有一个空间。最开始将name赋值“太白”,age赋值23,然后执行S2=Single('Alex',26),由于只有一个空间,故将此前的值覆盖掉,所以最后打印都是“Alex”。
(4)__str__方法
print(对象) 相当于调用一个对象的__str__方法
str(obj) 相当于执行了obj.__str__方法
'%s' % obj 相当于执行obj.__str__方法
1 # __str__方法2 classStudent:3 def __str__(self):4 return '%s %s %s' %(self.school,self.stu_cls,self.name)5
6 def __init__(self,name,stu_cls):7 self.school='oldboy'
8 self.name=name9 self.stu_cls=stu_cls10
11 he=Student('菏泽微','py14')12 # print(he) # 执行了__str__方法 结果:oldboy py14 菏泽微13 # print(str(he)) # 也执行了__str__方法,结果同上14 print('学生1:%s' % he) # 也执行了__str__方法,结果同上
【小结】所有的双下方法,没有需要你在外面调用的,而是总有一些其他的 内置函数 特殊的语法 来自动触发这些双下方法