python学习Day21--内置函数、反射

【知识点】

1、isinstance()  判断对象所属类型,包含继承关系

  type()与isinstance()的区别

1 class mystr(str):pass
2 ms=mystr('alex')
3 print(ms)
4 print(type(ms) is str)    # 不包含继承关系,只管一层
5 print(isinstance(ms,str)) # 包含所有的继承关系

2、issubclass(B,A)    判断B是不是A的子类(判断类与类之间的继承关系)

3、反射:用字符串数据类型的变量名来访问这个变量的值 

   方法:getattr   hasattr    setattr     delattr

 (1)在类的应用:静态属性(静态字段)、类方法、静态方法

   命名空间.XXX=getattr(命名空间,'XXX')   属性直接用,方法在后加()

 1 class Student:
 2     ROLE='STUDENT'
 3 
 4     @classmethod
 5     def check_course(cls):
 6         print("查看课程了")
 7 
 8     @staticmethod
 9     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 if hasattr(Student,num):         # 如果输入的num是Student这个命名空间里的方法,则返回True,否则返回Flase
21     getattr(Student,num)()
22 else:
23     num = input("你输入的有误,请重新输入要调用的方法>>>")

  (2)在对象中应用:

 1 # 在对象中
 2 class A():
 3     def __init__(self,name):
 4         self.name=name
 5 
 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 os
 3 '''
 4 # os.rename('__init__.py','init')
 5 # getattr(os,'rename')('init','__init__.py')
 6 rename=os.rename
 7 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 sys
22 # 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 class Manager():
 3     OPERATE_DIC=[
 4         ('create_student','创建学生账号'),
 5         ('create_course','创建学生课程'),
 6         ('check_student','查看学生信息')
 7     ]
 8 
 9     def __init__(self,name):
10         self.name=name
11 
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 class Student():
23     OPERATE_DIC = [
24         ('choose_course', '学生选择课程'),
25         ('check_course', '学生查询课程')
26     ]
27 
28     def __init__(self,name):
29         self.name=name
30 
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') as f:
44             for line in f:
45                 user,pwd,ident=line.strip().split('|')
46                 if username == user and password == pwd:
47                     print("登录成功")
48                     return username,ident
49                 else:
50                     print("输入错误,请重新输入,你还有%d次机会" % (3-count))
51                     break
52             count+=1
53 
54 import sys
55 def main():
56     while True:
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开始则需要添加起始参数1
63             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 class A:
 3     def __call__(self,*args,**kwargs):
 4         print("执行call方法了")
 5 
 6 class B:
 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 class Mylist:
 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         return len(self.__dict__)
12 m=Mylist()
13 print(len(m))   # 执行__len__方法了   3

(3)__new__方法(构造方法)

  在执行__init__之前,开辟一个空间。

 1 # __new__构造方法
 2 class Single:
 3     def __new__(cls,*args,**kwargs):
 4         obj=object.__new__(cls)
 5         print("在new方法里",obj)
 6         return obj
 7 
 8     def __init__(self):
 9         print("在init方法里",self)
10 #1、开辟一个空间,属于对象的
11 #2、把这个对象的空间传给self,执行init
12 #3、将这个对象的空间返回给调用者
13 obj=Single()         #结果:在new方法里 <__main__.Single object at 0x0000019F309D1978>
14                      #结果:在init方法里 <__main__.Single object at 0x0000019F309D1978>
15 #若是类中没有__nem__方法,则会调用object里的__new__来开辟空间

【一道面试题】

  写出一个单例类?

  #1、单例:如果一个类,从头到尾只能有一个实例(说明从头到尾只开辟了一块属于对象的空间),那么这个类就是一个单例类。

  单例的例子代码:

 1 # 写一个单例类
 2 class Single:
 3     __ISINSTANCE=None
 4     def __new__(cls,*args,**kwargs):
 5         if not cls.__ISINSTANCE:
 6             cls.__ISINSTANCE=object.__new__(cls)
 7         return cls.__ISINSTANCE
 8 
 9     def __init__(self,name,age):
10         self.name=name
11         self.age=age
12 
13 s1=Single('太白',23)
14 s2=Single('Alex',26)
15 print(s1.name)        # Alex
16 print(s2.name)        # Alex
17 # 原因:首先开辟一个空间,并且只有一个空间。最开始将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 class Student:
 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=name
 9         self.stu_cls=stu_cls
10 
11 he=Student('菏泽微','py14')
12 # print(he)    # 执行了__str__方法   结果:oldboy py14 菏泽微
13 # print(str(he))  # 也执行了__str__方法,结果同上
14 print('学生1:%s' % he)  # 也执行了__str__方法,结果同上

【小结】所有的双下方法,没有需要你在外面调用的,而是总有一些其他的 内置函数 特殊的语法 来自动触发这些双下方法

posted @ 2020-02-14 23:04  红叶楠木  阅读(163)  评论(0编辑  收藏  举报