面向对象鱼龙混杂

一.issubclass()

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

lass Foo:
    pass
class Bar(Foo):
    pass

print(issubclass(Bar, Foo))   # True
知识兔

  

二. isinstance()

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

lass 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()  判断一个属性是不是在对象中
#  getattr()  通过字符串获取属性和方法
# setattr()  通过字符串来设置属性和方法
# delattr()    通过字符串来删除属性和方法
知识兔

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

 动态的删除属性



# 原始的删除方法
p.name = 'lqz
print(p.__dict__)  # {'name': 'panshao'}
del p.name  # 直接拿属性
print(p.__dict__)  # {}


# 动态删除p中属性为变量a的属性
a = input('请输入要删除的属性:')
delattr(p, a)
知识兔

  

四. 内置方法

  __str__

lass Foo:
    pass
f = Foo()
print(f)
知识兔

  

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

lass 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 = namef = 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]=valuedi=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:    passf = 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')# 自定义元类:来控制类的产生,可以控制类名,可以控制类的关系(继承父类,控制类的名称空间)

  

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

class Mymeta(type):    def __call__(self, *args, **kwargs):                    # self是Person这个类                     # 实例化产生一个Person类的对象,借助__new__来产生,需要把类传过去,才能产生对象                     # obj 是Person类的对象,只不过是空的        obj = object.__new__(self)  # obj是空的        # 调用__init__方法实现初始化          self.__new__(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)    # nonep = 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 = agep1 = Person('panshao', 18)p2 = Person('bgon',19)print(p1)print(p2)

  

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

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

port = 3306host = '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._instances1 = 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=hostSql=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)
计算机