zoukankan      html  css  js  c++  java
  • 面向对象鱼龙混杂

    一.issubclass()

     判断第一个类是不是第二个类的子类, 返回True或者是false

    class Foo:
        pass
    class Bar(Foo):
        pass
    
    print(issubclass(Bar, Foo))   # True

    二. isinstance()

      判断第一个参数是不是第二个参数的对象,返回True或者false

    class Foo:
        pass
    class Bar:
        pass
    
    f = Foo()
    
    print(isinstance(f, Foo))   # True

    三. 反射

      主要是指程序可以访问, 检测和修改它本身的状态或者行为的一种能力,也就是自省的意思,程序在运行的过程中,他是可以修改,检测,访问的自己的属性,修改对象的方式可以用点来修改, 函数跟模块就不能用哪个点来进行修改,在Python设计之初,就是把一切看做对象,这里就用到反射.

    用户输入一段字符串,执行该字符串对应的方法
    class Foo:
        def run(self):
            print(run)
    
        def speak(self):
            print('speak')
    
    p = Foo()
    cmd = input('请输入命令:')
    
    if hasattr(p, cmd):   # 判断某个属性是不是在这个对象中
        run = getattr(p, cmd)
        run()
    else: 
        print('该命令不存在')
    
    
    key = input("请输入key:")
    value = input("请输入value:")
    setattr(p, key, value)   # 将key和value全都放置在p中
    print(p.age)   # 假如我们key设置为age,那么可以通过key就可以取出value值
    
    
    # 动态的往对象中放方法
    def test(a)
        print(a)
    print(p.__dict__)   # {}
    setattr(p, 'test', test)
    print(p.__dict__)  # {'test':<function test at 0x0000022B6ADFEA0>}
    p.test(0)
    
    
    
    # hasattr(obj, name)  判断obj中有没有name字符串的属性
    #  getattr(obj, name default)  通过字符串获取属性和方法
    # setattr(obj, key, value)  通过字符串来设置属性和方法
    # delattr(obj, name)    通过字符串来删除属性和方法

      有了反射的setattr方法,以后相加某个方法就可以随便的加了

    # 动态的删除属性
    
    
    
    # 原始的删除方法
    p.name = 'lqz
    print(p.__dict__)  # {'name': 'panshao'}
    del p.name  # 直接拿属性
    print(p.__dict__)  # {}
    
    
    # 动态删除p中属性为变量a的属性
    a = input('请输入要删除的属性:')
    delattr(p, a)
    

      

    四. 内置方法

      __str__

    class Foo:
        pass
    f = Foo()
    print(f)
    

      

     如果不重写__str__,print打印会打印出内存地址,如果重写了会打印出你想要的

    class Foo:
        def __str__(self):
            return 'xxx'
    f = Foo()
    print(f)    # 当print对象的时候就去调用里面的函数,相当于print(f.__str__())
    

      

      __repr__跟__str__相似, 在交互式的命令下直接写变量名,会执行__repr__,不用写print

      __setattr__, __delattr__, __getattr__(重要)

    class Foo:
        def __init__(self, name)
            self.name = name
    
    f = Foo('panshao')
    f.age    # 没有age 这个属性,就会出现报错 这时候就可以用__getattr__
    
    
    # __getattr__: 点拦截方法, 如果去对象中取属性, 取不到,会进入__getattr__,也就是 不存在的属性会哦方法
    
    class Foo:
        def __init__(self, name)
            self.name = name
        def __getattr__(self):
              print('的点点滴滴')
    
    f  = Foo()
    f.age      # 打印出的点点滴滴


    class Foo:
        def __init__(self, name)
            self.name = name
    
    f = Foo('panshao')  # 赋值时已经触发了__setattr__运行
    print(f.name)
    def __delattr__(self, item):  #self传的是调用者自己  itme传的是调用错误的函数信息
            print('----> from delattr')
            # del self.item #无限递归了
            #self.__dict__.pop(item)    #同理直接操作字典
    #__delattr__删除属性的时候会触发
    #del f1.x    #只要是删除操作就会调用__delattr__函数执行,值不存在也不会报错
    # f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
    # del f1.a
    # print(f1.__dict__)

    看一个例子:

     #写一个类继承字典,让它可以 . 取值,可以中括号取值
    class Mydict(dict):
        def __init__(self,**kwargs):
            super().__init__(**kwargs)
    
        def __getattr__(self, item):
            return self[item]
        def __setattr__(self, key, value):
            self[key]=value
    
    
    
    di=Mydict(name='lqz',age=18)
    print(di['name'])
    print(di.name)
    di.sex='male'
    di['sex']='male'
    print(di['name'])
    print(di.name)
     di.sex=19
     print(di.sex)
    di['sex']='male'
    print(di.sex)
    

      

      __call__   对象加括号会调用他

    class Foo:
        pass
    
    f = Foo()
    f()   # 报错
    
    
    
    class Foo:
        def __call__(self)
            print('xxx')
    
    f  = Foo()
    f()     #  xxxx
    

      

    五. 元类

      产生类的类就叫元类, type类是产生所有类的元类,type能够实例化产生object, type也能继承object,type是内置的一个元类,所有的类都是由type实例化得到

      class关键字底层实现原理:

    # class  类名 : 就会把类构造出来
    # 实际上是: 元类实例化产生类这个对象
    # 类实例化产生对象,一定是: 类名()
    # Person类是由type实例化产生,传一堆参数,也就是基类们
    # 然后拿到类的名称空间(执行类体代码,将产生的名字放到类的名称空间也就是一个字典里) # type(object_or_name, base, dict) object_or_name: 类的名字, 是个字符串 # base: 是他的所有父类,基类 # dict: 名称空间, 是个字典,有方法,有属性 class Person: # Person 是类也是对象 def __init__(self, name): self.name = name def score(self): print('分数是100分') p = Person('panshao')

      class的底层就是调用type来实例化产生类(对象), 自定义元类必须继承type, 写一个类继承type, 这种类就叫做元类

      通过元类控制类的产生:

    class Mymeta(type):
        pass
    # metaclass = Mymeta  指定这个类生成的时候,用自己写的Mymeta这个元类
    class Person(metaclass=Mymeta):   # Person 是类也是对象
        def __init__(self, name):
            self.name = name
        def score(self):
        
            print('分数是100分')
    
    p = Person('panshao')
    
    # 自定义元类:来控制类的产生,可以控制类名,可以控制类的关系(继承父类,控制类的名称空间)
    # 对象之所以能够调用,是因为对象的类中有一个函数__call__

      

      通过元类来控制类的产生过程:

    class Mymeta(type):
        def __call__(self, *args, **kwargs):
                        # self是Person这个类
                         # 实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象
                         # obj 是Person类的对象,只不过是空的
            obj = object.__new__(self)  # obj是空的
            # 调用__init__方法实现初始化
              self.__init__(obj, *args, **kwargs)   # 类来调用__init__方法,就是个普通函数,有几个参数就传几个参数
             # obj.__new__(*args, **kwargs)  # 对象来调用__init__方法,对象的绑定方法,会把自身传过来
    class Person(metaclass=Mymeta):   
        def __init__(self, name):
            self.name = name
        def score(self):
            print('分数是100分')
        def __call__(self):
            print("11111")
    
    p = Person('panshao')   # 自动触发init的执行   Person加括号就是调用元类的call方法
    # 先触发元类的__call__
    p()     # p()是调用person的call
    

      

      __new__:

    class Person:
        def __init__(self, name, age)
            print("__init__")
            self.name = name
            self.age = age
        def __new__(cls, *args, **kwargs):
            # print("__new__")
            # 生成一个空对象, return出去,在元类的__call__里调用了__init__来完成初始化
             return object.__new__(cls)
    
    p = Person('panshao', 18)    # 打印出__new__      奇怪为什么没有触发__init__, 
    
    print(p)    # none
    
    
    
    
    
    p = Person('panshao', 18)    # 打印出__new__      奇怪为什么没有触发__init__, p = Person('panshao', 18)先调用__call__方法,__call__再调用自己的self的__new__,就会得到一个空对象,假如我在__new__的方法中return一个1,那么这个空对象就是1,return后面的空对象一旦有值才会调用__init__
    

      __new__和__init__的区别: __new__创建对象,必须有返回值, __init__初始化对象,就是给对象穿衣服

      object.__new__(Person):  生成person类的对象, 空的

      type.__new__(cls, name, bases, dic):  生成class这个类对象, 里面有东西

      type类: __call__: 1. 调用Mymeta的__new__,得到类对象, 2. 调用Mymeta的__init__,完成对类对象的初始化

      自定义的Mymeta元类: __call__  1.调用了Person类的__new__,得到对象, 2. 调用Person类的__init__, 完成对象的初始化

    六. 单例模式(23中设计模式的一种)

      整个过程中只有一个实例, 所有生成的实例都指向同一块内存空间

    class Person:
        def __init__(self, name , age)
            self.name = name
            self.age = age
    
    p1 = Person('panshao', 18)
    p2 = Person('bgon',19)
    print(p1)
    print(p2)
    

      

    像上面这种情况就不是单例模式,他实例化出两个对象,单例模式是每次实例化出现的是同一个对象

      实现单例的第一种方式:通过类的绑定方法

    port = 3306
    host = '127.0.0.1'
    class Sql:
        _instance = None
        def __init__(self, port, host):
            self.port = port
            self.host = host
        @classmethod
        def get_sigleton(cls):
             if not cls._instance:
                    cls._instance = cls('port', 'host')
            return cls._instance
    
    s1 = Sql.get_sigleton()
    s2 = Sql.get_sigleton()
    # 这样调用的话会实例化出不同的结果,我们现在做的就是要求每次拿到的实例化的结果都是一样的,我们可以在类的名称空间中加一个属性_instance
    

      拿到的结果都是一样的,其实就是我每次要值得话,就去名称空间里面去取值就行

      第二种方法: 通过装饰器

    第二种方法:通过装饰器
    当用户输入端口和地址,实例化产生新对象
    当用户不输入端口和地址,每次拿到的对象,都是同一个
    def get_sigoleton(cls):
         #cls就是Sql这个类
         import settings
         _instance=cls(settings.PORT, settings.HOST)
         _instance=Sql(settings.PORT, settings.HOST)
    
        def wrapper(*args,**kwargs):
            if len(args)!=0 or len(kwargs)!=0:
                #表示传了参数,生成新对象
                res=cls(*args,**kwargs)
                return res
           else:
                return _instance
         return wrapper
    
     def get_sigoleton(cls):
         _instance=None
         def wrapper(*args,**kwargs):
             if len(args)!=0 or len(kwargs)!=0:
                 #表示传了参数,生成新对象
                 res=cls(*args,**kwargs)
                 return res
            else:
                 import settings
                 nonlocal _instance
                if not _instance:
                     _instance=cls(settings.PORT, settings.HOST)
                return _instance
         return wrapper
    @get_sigoleton    #会把下面的Sql当中参数传入,相当于:Sql=get_sigoleton(Sql)
    class Sql():
         def __init__(self,port,host):
            self.port=port
            self.host=host
    Sql=get_sigoleton(Sql)
     s1=Sql()
    s2=Sql()
    s3=Sql('33306','192.168.1.1')
    s4=Sql('33306','192.168.1.1')
     print(s1)
    print(s2)
    print(s3)
    

      

      第三种: 通过元类

    #第三种,通过元类
    #当用户输入端口和地址,实例化产生新对象
    #当用户不输入端口和地址,每次拿到的对象,都是同一个
    
    # class Mymeta(type):
    #     def __init__(self,name,bases,dic):
    #         #self 是Sql类
    #         import settings
    #         #把实例化好的对象,放到了类的名称空间
    #         self._instance=self(settings.PORT, settings.HOST)
    #     def __call__(self, *args, **kwargs):
    #         #self是谁?是Sql类
    #         if len(args)!=0 or len(kwargs)!=0:
    #             obj=object.__new__(self)
    #             obj.__init__(*args, **kwargs)
    #             return obj
    #         else:
    #             return self._instance
    #
    # class Sql(metaclass=Mymeta):    #相当于 Sql=Mymeta(name,bases,dic)   这个会调用 Mymeta的__init__  在里面已经向类的名称空间放了一个对象
    #     def __init__(self,port,host):
    #         self.port=port
    #         self.host=host
    #
    # print(Sql.__dict__)
    # s1=Sql()
    # #调用元类的__call__
    # s2=Sql()
    # s3=Sql('33306','192.168.1.1')
    # print(s1)
    # print(s2)
    # print(s3)
    
    生前无需久睡,死后自会长眠,努力解决生活中遇到的各种问题,不畏将来,勇敢面对,加油,你是最胖的,哈哈哈
  • 相关阅读:
    Bellman-Ford(BF)和Floyd算法
    Dijkstra实现最短路径
    【图论】连通分量个数(并查集)
    【模拟】n a^o7 !
    【图论】最小生成树
    【搜索DFS】图的深度遍历(dfs)
    【搜索BFS】poj3278--Catch That Cow(bfs)
    【图论】判断给定图是否存在合法拓扑序列
    二叉排序树
    【树】判断给定森林中有多少棵树(简单做法)
  • 原文地址:https://www.cnblogs.com/panshao51km-cn/p/11618911.html
Copyright © 2011-2022 走看看