1.补充两个类这里相关的内置函数:
issubclass(子类,父类) 用于判断前者是不是后者的子类
isinstance(对象,类) 用于判断前者是不是后者这个类的对象
这种判断是广义的,有深度,包含被继承的父类们的....
对象 is type(类) 这种判断是狭义的,不继承,只限于后面给出来的类
2.反射:
反射是指:用字符串类型的变量名来访问这个变量
使用场景:用户的输入内容是字符串类型的,且是不安全的.如何获取字符串的内容并安全地调用是反射的具体应用
2.1 使用类名进行反射:
命名空间.XXX 等效于 getatter(命名空间,'XXX')
#命名空间.XXX 等效于 getatter(命名空间,'XXX') class Student: ROLE = 'STUDENT' @classmethod def check_course(cla): print('查看所有课') @staticmethod def login(): print('登录') print(Student.ROLE) #用户输入的内容是字符串,如果用eval()处理,容易崩,慎用,网络来源的数据和用户输入的是不能用的 print(getattr(Student,'ROLE')) #后面的是变量名且确实是字符串 #第一个参数的命名空间的变量名为第二个参数的值 #反射调用方法 print(getattr(Student,'check_course')) #打印的是对应的方法地址,方法名加括号即执行,见下 getattr(Student,'check_course')() getattr(Student,'login')()
这是一种安全措施,先由hasattr()函数确定所输入内容在这个类中再调用,不在则另行处理,hasattr()和getattr()通常配套使用
num = input('输入') print(hasattr(Student,num) ) #用于判断输入的内容在前面这个类中到底有没有,无则F,有则T
if hasattr(Student,num):
getattr(Student,num)()
2.2利用对象调用反射和类的调用基本相同
2.3利用模块调用反射自己模块当中的内容,需找到自己当前文件所在的命名空间
import 模块
getattr(模块,'名字')=模块名.方法名=调用这个方法,再给它加括号和参数即可调用
2.4利用模块调用反射自己文件当中的内容,需找到自己当前文件所在的命名空间
import sys
getattr(sys.modules['__main__'],'名字')=自己文件.名字=调用这个方法,再给它加括号和参数即可调用
3.内置方法
__call__方法
对象名加括号,自动执行__call__
可以在构造函数内把别的类实例化为的一个对象作为self的属性(就是一种组合),然后调这个属性的__call__
__len__方法
类外执行len(对象)相当于调用这个对象对应类内的__len__方法,具体内容自己设置
__new__方法
用于开辟内存空间,一般自定义的类在实例化的时候都无法自己开辟空间,自动去找父亲object里的了,其返回值传给了self,在双init之前执行。
在执行双下new方法之前是没有产生self的,其方法默认函数只能写cls
单例类:
如果一个类从头到尾只能创建一个实例,那么就是个单例类。一般的类是可以随便无穷无尽进行实例化的。
单例则说明从头到尾只开辟了一个空间
先在类里设置一个值为空的私有属性,在双下new执行前加一个该私有属性是否为空的判断,是则开辟,不是则返回之前开出来的内容(即这个私有属性)
背住!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
class Single: __stayrom = None def __new__(cls, *args, **kwargs): #__new__的作用是开辟一块内存地址出来,然后将其传给对象的self if not cls.__stayrom: cls.__stayrom = object.__new__(cls) else: return cls.__stayrom def __init__(self, name): pass s1 = Single()
无论是实例化几次都是对同一块内存地址的内容进行操作
输出的结果是最终实例化之后反复覆盖的结果
__str__方法
1.打印对象名,就可以直接调用双下str方法。
2.str(对象名)等于obj.双下str
3.格式化输出的对象名,也相当于格式化输出__str__方法 的返回值'%s'/%obj,相当于执行obj.__str__方法