1. 程式人生 > >內建函式isinstance,issubclass ,反射,自定義內建方法來定製類的功能,元類

內建函式isinstance,issubclass ,反射,自定義內建方法來定製類的功能,元類

一:內建函式 

     1,isinstance 判斷某個物件是不是屬於某一型別?

        class Foo:
            pass
        obj=Foo()

        print(isinstance(obj,Foo))# 在python3中統一類與型別的概念返回True 或者False

      2,issubclass 判斷一個類是不是另一個類的子類

        class Parent:
            pass
        class Sub(Parent):
            pass
        print(issubclass(Sub,Parent))

        print(issubclass(Parent,object))#返回True或者False

二:反射

        反射:就是通過字串來操作類或者物件的屬性

        用:hasattr
               getattr
                setattr
                delattr

       class People:
            country='China'
            def __init__(self,name):
                self.name=name
            def eat(self):
                print('%s is eating' %self.name)
            peo1=People('egon')
            # print(hasattr(peo1,'eat')) #peo1.eat
            # print(getattr(peo1,'eat')) #peo1.eat
            # print(getattr(peo1,'xxxxx',None))
            # setattr(peo1,'age',18) #peo1.age=18
            # print(peo1.age)
            # print(peo1.__dict__)
            # delattr(peo1,'name') #del peo1.name

            # print(peo1.__dict__)     

             應用場景:

                class Ftp:
                    def __init__(self,ip,port):
                        self.ip=ip
                        self.port=port
                    def get(self):
                        print('GET function')
                    def put(self):
                        print('PUT function')
                    def run(self):
                        while True:
                            choice=input('>>>: ').strip()#接收使用者輸入的字串對映到具體的屬性
                            # print(choice,type(choice))
                            # if hasattr(self,choice):
                            #     method=getattr(self,choice)
                            #     method()
                            # else:
                            #     print('輸入的命令不存在')
                            method=getattr(self,choice,None)
                            if method is None:
                                print('輸入的命令不存在')
                            else:
                                method()
                    conn=Ftp('1.1.1.1',23)
                    conn.run()

  三:自定義內建函式方法?

                #1、__str__方法
                # class People:
                #     def __init__(self,name,age):
                #         self.name=name
                #         self.age=age

                #     #在物件被列印時,自動觸發,應該在該方法內採集與物件self有關的資訊,然後拼成字串返回

                #     def __str__(self):
                #         # print('======>')
                #         return '<name:%s age:%s>' %(self.name,self.age)
                # obj=People('egon',18)
                # obj1=People('alex',18)
                # print(obj)  #obj.__str__()
                # print(obj)  #obj.__str__()
                # print(obj)  #obj.__str__()
                # print(obj1)  #obj1.__str__()

                #1、__del__析構方法
                # __del__會在物件被刪除之前自動觸發#只要是針對物件使用的
                class People:
                    def __init__(self,name,age):
                        self.name=name
                        self.age=age
                        self.f=open('a.txt','rt',encoding='utf-8')
                    def __del__(self):
                        # print('run=-====>')
                        # 做回收系統資源相關的事情
                        self.f.close()
                obj=People('egon',18)#物件obj已經被創建出來之後不會受類的影響,刪除類之後也不會影響物件的使用

                print('主') 

四:元類

           4.1, 元類:在python中一切皆物件,那麼我們用class 關鍵字定義的類本身也是一個物件。關鍵字定義的類本身也是一個物件。

            4.2,為什麼要用元類:元類是負責產生類的,所以我們學習元類或者自定義元類的目的是為了控制類的產生過程,還可以控制物件的產生過程

            4.3  使用:

                #1、儲備知識:內建函式exec的用法
                # cmd="""
                # x=1
                # def func(self):
                #     pass
                # """
                # class_dic={}
                # exec(cmd,{},class_dic)#excu用來模擬python直譯器解釋執行字串格式的程式碼

                # print(class_dic)#得到一個名稱空間放到class—dic中去

                #2、建立類的方法有兩種
                # 大前提:如果說類也是物件的化,那麼用class關鍵字的去建立類的過程也是一個例項化的過程
                # 該例項化的目的是為了得到一個類,呼叫的是元類
                #2.1 方式一:用的預設的元類type
                # class People: #People=type(...)
                #     country='China'
                #     def __init__(self,name,age):
                #         self.name=name
                #         self.age=age
                #     def eat(self):
                #         print('%s is eating' %self.name)
                # print(type(People))

                #2.1.1 建立類的3個要素:類名,基類,類的名稱空間
                class_name='People'
                class_bases=(object,)#基類寫成元祖形式,用內建方法__bases__檢視基類
                class_dic={}
                class_body="""   #類體程式碼
                country='China'
                def __init__(self,name,age):
                self.name=name
                self.age=age
                def eat(self):

                    print('%s is eating' %self.name)

                    """

                 exec(class_body,{},class_dic)

                # 準備好建立類的三要素
                # print(class_name)
                # print(class_bases)
                # print(class_dic)
                # People=type(類名,基類,類的名稱空間)
                # People1=type(class_name,class_bases,class_dic)
                # print(People1)
                # obj1=People1('egon',18)
                # print(People)
                # obj=People('egon',18)
                #
                # obj1.eat()
                # obj.eat()

                #2.2 方式二:用的自定義的元類
                class Mymeta(type): #只有繼承了type類才能稱之為一個元類,否則就是一個普通的自定義類
                    def __init__(self,class_name,class_bases,class_dic):
                        print(self) #現在是People
                        print(class_name)
                        print(class_bases)
                        print(class_dic)
                        super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父類的功能    

                # 分析用class自定義類的執行原理(而非元類的的執行原理):
                #1、拿到一個字串格式的類名class_name='People'
                #2、拿到一個類的基類們class_bases=(obejct,)
                #3、執行類體程式碼,拿到一個類的名稱空間class_dic={...}
                #4、呼叫People=type(class_name,class_bases,class_dic)
                class People(object,metaclass=Mymeta): #People=Mymeta(類名,基類們,類的名稱空間)
                    country='China'
                    def __init__(self,name,age):
                        self.name=name
                        self.age=age
                    def eat(self):

                        print('%s is eating' %self.name) 

                 # 應用:自定義元類控制類的產生過程,類的產生過程其實就是元類的呼叫過程
                class Mymeta(type): #只有繼承了type類才能稱之為一個元類,否則就是一個普通的自定義類
                    def __init__(self,class_name,class_bases,class_dic):
                        if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0:
                            raise TypeError('類中必須有文件註釋,並且文件註釋不能為空')
                        if not class_name.istitle():
                            raise TypeError('類名首字母必須大寫')
                        super(Mymeta,self).__init__(class_name,class_bases,class_dic) #重用父類的功能
                class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....})
                    """這是People類"""
                    country='China'
                    def __init__(self,name,age):
                        self.name=name
                        self.age=age
                    def eat(self):
                        print('%s is eating' %self.name)

            #3 儲備知識:__call__
            # class Foo:
            #     def __call__(self, *args, **kwargs):
                #         print(self)
                #         print(args)
                #         print(kwargs)
                # obj=Foo()
                #
                # # 要想讓obj這個物件變成一個可呼叫的物件,需要在該物件的類中定義一個方法__call__方法
                # # 該方法會在呼叫物件時自動觸發
                # obj(1,2,3,x=1,y=2)                      

            # 4、自定義元類來控制類的呼叫的過程,即類的例項化過程
            class Mymeta(type):
                def __call__(self, *args, **kwargs):
                    # print(self) # self是People
                    # print(args)
                    # print(kwargs)
                    # return 123
                    # 1、先造出一個People的空物件
                    obj=self.__new__(self)
                    # 2、為該對空物件初始化獨有的屬性
                    # print(args,kwargs)
                    self.__init__(obj,*args,**kwargs)
                    # 3、返回一個初始好的物件
                    return obj

            class People(object,metaclass=Mymeta):
                country='China'
                def __init__(self,name,age):
                    self.name=name
                    self.age=age
                def eat(self):
                    print('%s is eating' %self.name)
                def __new__(cls, *args, **kwargs):
                    print(cls)
                    # cls.__new__(cls) # 錯誤
                    obj=object.__new__(cls)
                    return obj
            # 分析:呼叫Pepole的目的
            #1、先造出一個People的空物件
            #2、為該對空物件初始化獨有的屬性
            # obj1=People('egon1',age=18)
            # obj2=People('egon2',age=18)
            # print(obj1)
            # print(obj2)
            obj=People('egon',age=18)
            print(obj.__dict__)
            print(obj.name)
            obj.eat()