zoukankan      html  css  js  c++  java
  • exec , 元类,__new__, __call__ , 单例模式 , 异常

    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")
  • 相关阅读:
    [LeetCode] Convert Sorted Array to Binary Search Tree
    [LeetCode] Diameter of Binary Tree
    [LeetCode] Student Attendance Record I
    [LeetCode] Reverse String II
    [LeetCode] Missing Number
    [LeetCode] Intersection of Two Arrays II
    [LeetCode] Base 7
    Ubuntu中firefox设置成中文
    Linux中的查找命令find
    Ubuntu14.04安装配置Chrome浏览器
  • 原文地址:https://www.cnblogs.com/HZLS/p/10925601.html
Copyright © 2011-2022 走看看