1,类也是对象
''' 动态语言 可以在运行期间 动态生成类 修改对象属性 静态语言 ''''' ''' type(object_or_name, bases, dict) type(object) -> the object's type type(name, bases, dict) -> a new type ''' obj = type("TestClass",(object,),{}) print(obj) #<class '__main__.TestClass'> class B(object): #type("B",(object,),{"name":"rose"}) name = "rose" #模拟解释器创建类的过程 def test1(a): print(a) def test2(self,b): print(self,b) class_name = "C" bases = (object,) name_dic = {"name":"jack","test1":test1,"test2":test2} C = type(class_name,bases,name_dic) # print(C) #<class '__main__.C'> c1 = C() print(c1) #<__main__.C object at 0x000001EFEC877550> c1.test2(100) #<__main__.C object at 0x0000021F31807550> 100
2 , exec
glob = {} locl = {} code = """ def test(a): print(a) """ exec(code,glob,locl) # print(glob) #打印系统内置函数 print(locl) #{'test': <function test at 0x000001376F36C2F0>} locl["test"](100) #exec 可以执行字符串形式的python代码,并且会把执行过程中产生的名字,放到局部名称空间中 class_test = """ class A: def test(self): print(self) """ loca2 = {} exec(class_test,None,loca2) print(loca2) #{'A': <class '__main__.A'>} # eval(class_test) #报错,eval用于处理单行字符串的表达式
3,元类
class person(): def __init__(self,name): self.name = name def SAYHI(self): print(self.name) ''' 类名必须大写开头,方法名必须全部小写 应用场景:用于限制类,满足某些条件,例如上述要求 type类已经具备了创建类的能力,但是现在不能满足我们的要求 需要对已有的功能进行扩展或修改 方式: 1,直接修改源代码 ,行不通 2,自定义新的元类 ''' class MyMetaClass(type): pass #默认创建类时,是找的type来实例化的 class Person(metaclass=MyMetaClass): pass class Student: def __init__(self): pass print(type(Person)) #<class '__main__.MyMetaClass'> print(type(Student)) #<class 'type'> s = Student() #实例化对象时, 1,产生空对象,2,自动执行__init__ #创建类对象时也是一样的,会先创建空的类对象,在调用__init__()方法 # Person = MyMetaClass()
class MyMetaClass(type): def __init__(self,class_name,bases,name_dic): #元类中的self表示的都是类对象 print(self) #<class '__main__.Student'> #不要忘记调用父类的初始化 super().__init__(class_name,bases,name_dic) print(name_dic) #类名必须首字母大写,否则直接抛出异常 if not class_name.istitle(): print('类名必须大写!') raise Exception #控制类中方法名必须全部小写 for k in name_dic: if str(type(name_dic[k])) == "<class 'function'>": if not k.islower(): raise Exception('方法名必须全小写!') #会自动调用其元类中的__init__方法传入,类对象本身,类名称,父类们,名称空间 class Student(object,metaclass=MyMetaClass): #MyMetaClass("Student",(object,),{}) NAME = 10 def asdfA(self): print('SNY')
3 , 元类中 __new__
class MeMetaClass(type): def __init__(self,class_name,bases,name_dic): # super().__init__(class_name,bases,name_dic) print("init") #该方法会在实例化类对象时自动调用并且在__init__之前调用 #其作用是用于创建新的类对象的 #注意这里必须调用type类中的__new__否则将无法产生类对象,并且返回其结果 def __new__(cls, *args, **kwargs): #cls 表示元类自己即MyMetaClass print("new") print(args,kwargs) #('Person', (), {'__module__': '__main__', '__qualname__': 'Person'}) {} return type.__new__(cls,*args,**kwargs) #如果覆盖__new__一定要写上这行代码 class Person(metaclass=MeMetaClass): pass print(Person) #<class '__main__.Person'> #就算__init__中什么都不写,这个类对象其实已经创建完成了,该有的属性都有了 #这是与普通类不同之处 print(Person.__name__) #不会报错 class Student: def __init__(self,name): pass s = Student('张三') # s.name #报错
#练习1:
#需求:要求每个类必须包含__doc__属性,__doc__用于访问一个对象的注释信息 class A: ''' this is A ''' pass print(A.__doc__) #如果你要控制类的创建,那就自定义元类 覆盖__init__ class DocMetaClass(type): def __init__(self,class_name,bases,name_dic): super().__init__(class_name,bases,name_dic) # if not("__doc__" in name_dic and name_dic["__doc__"]): # raise Exception #如果doc为空,则抛异常 if not self.__doc__: raise Exception class Person(metaclass=DocMetaClass): pass print(type(object))
4 , 元类中 __call__
class Person: #调用对象时,会执行对象所在类中的__call__方法 def __call__(self, *args, **kwargs): print("call") print(args) print(kwargs) p = Person() p() ''' 练习:将类中的为字符串的属性名转为大写 ''' class MyMeta(type): #获得某个类的实例 def __call__(self, *args, **kwargs): print("call") # return super().__call__(*args,**kwargs) print(args) #('jack', 'women', 18) print(kwargs) #{} new_args = [] for i in args: if isinstance(i,str): new_args.append(i.upper()) else: new_args.append(i) print(new_args) #['JACK', 'WOMEN', 18] return super().__call__(*new_args,**kwargs) #注意:__new__ __init__是创建类对象时还会执行 #__call__ 类对象要产生实例时执行 class Student(metaclass=MyMeta): def __init__(self,name,gender,age): self.name = name self.gender = gender self.age = age s = Student('jack','women',18) print(s.age) #18 print(s.gender) #WOMEN class Person(metaclass=MyMeta): def __init__(self,name,gender): self.name = name self.gender = gender p = Person('rose','name') print(p.name) #ROSE
5, 单例模式
''' 单例模式 是一种设计模式,是单个实例的意思 当你需要 让你的类仅有一个实例时,那就可以使用单例模式 ''''' class Person: obj = None def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def say(self): print('my name is %s my 姑姑 is 龙妈'%self.name) @classmethod def get_instance(cls): if not cls.obj: obj = cls('小龙女',19,'women') cls.obj = obj print('创建新的了') return cls.obj # 调用了多次,产生了多个实例 (地址不一样) p1 = Person('姬如雪','20','women') p1.say() p2 = Person('姬如雪','20','women') p2.say() print(p1,p2) #<__main__.Person object at 0x000001A5A87076A0> <__main__.Person object at 0x000001A5A8707710> #限制了类的实例化,如果为同一个类则只实例化一次 (地址一样) p1 = Person.get_instance() p1.say() p2 = Person.get_instance() p2.say() print(p1) #<__main__.Person object at 0x000002396C2F75C0> print(p2) #<__main__.Person object at 0x000002396C2F75C0>
6 , 元类实现单例
class SingMeta(type): # 创建类时会执行__init__,在这为每一类设置一个obj属性 默认为None def __init__(self, a, b, c): super().__init__(a, b, c) self.obj = None print(self.obj) # 当类要创建对象时会执行该方法 def __call__(self, *args, **kwargs): # 判断这个类如果已经有了实例了就直接返回,从而实现单例 if self.obj: return self.obj # 如果没有,则创建新的实例保存到类中 obj = type.__call__(self, *args, **kwargs) self.obj = obj return obj class Person(metaclass=SingMeta): def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender def say(self): print("my name is %s my 姑姑 is 龙妈" % self.name) class Student(metaclass=SingMeta): def __init__(self, name, age, gender): self.name = name self.age = age self.gender=gender def say(self): print("my name is %s my 姑姑 is 龙妈" % self.name) p1 = Person('姬如雪',20,'women') p2 = Person('姬如雪',20,'women') print(p1) #<__main__.Person object at 0x000001F512867668> print(p2) #<__main__.Person object at 0x000001F512867668> stu1 = Student('史蒂夫',18,'man') stu2 = Student('史蒂夫',18,'man') print(stu1) #<__main__.Student object at 0x0000013B18EB7780> print(stu2) #<__main__.Student object at 0x0000013B18EB7780>
7, 单例案例:
class Single(type): def __init__(self,a,b,c): super().__init__(a,b,c) self.obj = None def __call__(self, *args, **kwargs): if self.obj: return self.obj obj = type.__call__(self,*args,**kwargs) self.obj = obj return obj class QQPlayer(metaclass=Single): def __init__(self,voice_value,repeat=False): self.voice_value =voice_value self.repeat = repeat def play(self,file_path): if hasattr(self,'file_path'): self.stop() print('正在播放%s'%file_path) self.file_path = file_path def stop(self): print('%s--停止播放'%self.file_path) #问题:每次播放一次,都是实例化一次 ply = QQPlayer(100,True) ply.play('如果.mp3') ply1 = QQPlayer(100,True) ply1.play('后来.mp3') ply2 = QQPlayer(100,True) ply2.play('田鸥.mp3') print(ply) #<__main__.QQPlayer object at 0x000002B349C87550> print(ply1) #<__main__.QQPlayer object at 0x000002B349C87550> print(ply2) #<__main__.QQPlayer object at 0x000002B349C87550>
8, 常见异常
''' 语法错误: SyntaxError: invalid syntax ''''' # if num > 1 # print('hello') # a = # b = 10 ''' 类型错误: TypeError: 'int' object is not subscriptable ''' # 1[:] ''' 下标错误: IndexError: list index out of range ''' # li = [1,2,3,4] # print(li[10]) ''' KeyError: 'xxx' ''' # {'name':1}['xxx'] ''' FileNotFoundError: [Errno 2] No such file or directory: 'xxx' ''' # with open('xxx')as f: # pass ''' NameError: name 'name' is not defined ''' # def func(): # name # pass # func() ''' 1,捕捉异常 ''' #语法一: try: print('start') {'name':1}['xxx'] print('over') except: print(' key 不存在')
#语法二: 在except 中指定要处理的异常类型 try: print('start') {'name':1}['xxx'] 1[:] print('over') except KeyError: print('出问题了')
#语法三 : 在except中可以指定多种异常类型,使用统一的处理方案,没啥用 try: print('start') {'name':1}['xxx'] 1[:] print('over') except(KeyError,TypeError): print('出问题了')
#语法四 : 一个try可以跟多个except语句 每个处理不同的异常 try: print('start') {'name': 1}['xxx'] 1[:] print('over') except KeyError: print('Key 不存在!') except TypeError: print('要操作的类型不对啊!') # 语法5 万能异常 尽量少用 因为 无法知道具体原因 try: print("start") # {"name":1}["xxx"] # 1[:] # name print("over") except Exception: print("不知道啥原因 反正有问题!")
# 语法6 给异常对象取别名 从而访问一异常对象 # 之所以 能处理任何类型 是因为 Exception 是所有异常类的父类 try: print("start") # {"name":1}["xxx"] 1[:] # name print("over") except Exception as e: print("有问题! 原因为%s" % e) print(type(e)) # 最常用的方式 在处理异常时 一定要记得打印一下异常信息 否则 你的程序不会出问题 但是也不会正常运行 try: name except NameError as e: print(e) # 观光语法 else 将在代码没有异常时执行 try: a = 10 except Exception as e: print(e) else: print("else???????? ") class FileTypeException(Exception): pass class Player: def play(self,path): if not path.endswith("mp3"): # print("文件类错误!") # z主动抛出异常 raise FileTypeException("仅能播放mp3格式.....") print("播放%s" % path) assert path.endswith("mp3") print("播放%s" % path) p = Player() p.play("xxx.mp4")