面向对象鱼龙混杂

Posted panshao51km-cn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象鱼龙混杂相关的知识,希望对你有一定的参考价值。

一.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()  判断一个属性是不是在对象中
#  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__

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‘)

# 自定义元类:来控制类的产生,可以控制类名,可以控制类的关系(继承父类,控制类的名称空间)

  

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

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)    # 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)

 

以上是关于面向对象鱼龙混杂的主要内容,如果未能解决你的问题,请参考以下文章

前端之JavaScript面向对象开发

大家一起和snailren学java-一切都是对象

面向对象编程——面向对象和面向过程

三. python面向对象

224 面向对象编程介绍,面向过程与面向对象

面向对象-面向对象和面向过程的区别