元类回顾

type 只传一个参数时有什么用: 作用是打印对象的类型

class 底层原理:通过type类来实例化得到类

def __init__(self, name):
    self.name=name
Person = type('Person', (object,), {'x':1, '__init__': __init__})
p=Person('Nick')
print(Person.__dict__)
print(p.__dict__) #{'name': 'Nick'}
print(p.name)#Nick
等同于如下
class Person(object):
    x = 1
    def __init__(self,name):
        self.name=name
p=Person('Nick')
print(Person.__dict__)
print(p.__dict__)#{'name': 'Nick'}
print(p.x)#1
print(p.name)#Nick

exec 执行字符串的代码,当成python解释器(就是把有一串字符串丢进去会被执行)

ss='''
x=1
print(x)
'''
g={}
l={}
exec(ss, g, l)
print(l)  #1 /{'x': 1} (把ss里面的字符串全部放在了l这个局部名称空间,打印执行l时先执行了字符串里面的(print(x)),再执行打印了(print(l))

自定义元类:继承type

# 自定义元类:继承type
class Mymeta(type): #自定义元类必须继承type
    def __init__(self, name, bases, dic):
        #self是Person这个类对象(要创建的类名)
        #在这个位置,其实self也就说Person这个类,内部空间已经有东西了,名称空间里已经有东西了(Mymeta类实例化,会把Person的三个参数传到Mymeta的__init__方法中
        #所有这个地方可以通过dic来判断名称空间
        #也可以直接通过self.__dict__/self.属性 来判断
        a=dic.get('name')
        if not a:
            raise Exception('没有name属性,不能创建')
    # def __call__(self, *args,**kwargs):
    #     pass

class Person(metaclass=Mymeta):  #Person=Mymeta('Person', (object,),{...}) Mymeta类实例化,会把三个参数传到Mymeta的__init__中
    name='Nick'

    def __init__(self,age):
        self.age=age
        #raise Exception('就不让你创建')
print(Person.__dict__)
p=Person(18)
print(p) #<__main__.Person object at 0x0000000009F82BA8>
print(p.age) #18
print(p.name) #Nick
 #注:如果在元类中定义了__call__,就必须有返回值(对象),否则无法生成对象
# 总结:可以通过自定义元类,重写__init__方法来控制类的产生(重写__init__就是在元类的init下做一些设置(判断条件等))

通过元类控制类的调用过程,实例化产生对象的过程

# 通过元类控制类的调用过程,实例化产生对象的过程
class Mymeta(type):
    def __call__(self, *args, **kwargs):
        #该方法必须返回一个(类对象),这个地方返回什么,p=Person('lqz') p就是什么

        #返回一个真正的Person类对象
        #第一步:产生一个空对象
        object.__new__(self) #传一个参数,传类,就会产生一个该类的空对象(得到空对象obj)
        obj=object.__new__(self)
        #obj是Person的空对象
        #print(self.__new__ is object.__new__) #True

        #第二步:初始化该对象,把初始值放到对象中
        #obj是Person类的空对象  obj.__init__ 调用自己的绑定方法(Person下的init方法)
        obj.__init__(*args, **kwargs) #类的绑定方法
        #还可以类来调用
        #Person.__init__(obj, *args,**kwargs)
        #self.__init__(obj, *args,**kwargs) (self其实就是Person)
        return obj
class Person(metaclass=Mymeta):
    def __init__(self,name):
        self.name=name
    def __call__(self,*args,**kwargs):
        print('xxx')
p=Person('Nick')
print(p.name) #Nick
print(p) #<__main__.Person object at 0x00000000025F9710>
# 原来的理解Person('Nick')会调用Person类的__init__的方法
# 现在理解:这个位置会先调用元类的__call__方法,然后在__call__方法中调用了Person的__init__的方法,来完成对象的初始化
p() #xxx  p()会调用Person的__call__方法

模板:控制对象的产生模板

class Mymeta(type):
	def __call__(self, *args, **kwargs)
        obj=object.__new__(self)
        obj.__init__(*args,**kwargs)
        return obj
class Person(metaclass=Mymmeta):
    def __init__(self, name)
    	self.name=namem
    def __call__(self, *args, **kwargs)
    	print('xxx')
p=Person('Nick')   

昨天的作业

class Mymeta(type):
    def __call__(self,name,age):
        obj=object.__new__(self)
        obj.__dict__['attr']={'name':name,'age':age}
        return obj
class Person(metaclass=Mymeta):
    def __init__(self,name,age):
        self.name=name
        self.age=age
p=Person('Nick',18)
print(p.__dict__)
print(p.attr['name']) #Nick

赠送知识点

class Person():
    def __init__(self,name,age):
        print('__init__')
        self.name=name
        self.age=age
    def __new__(cls, *args, **kwargs):
        print('__new__')
        #生成一个Person类的空对象
        return object.__new__(cls)
p=Person('Nick',18)
print(p) # <__main__.Person object at 0x000000000296F0B8>
# 先执行__new__生成一个空对象,在执行__init__完成对象的初始化
objcet.__new__ 传哪个类就得到哪个类的空对象
p=object.__new__(Person)
print(p)

_ _new _ _ 和 _ _init _ _的区别

# __new__ 创建空对象
# __init__ 初始化空对象

# object.__new__(Person) :生成Person类的对象  空的
# type.__new__(cls, name, (object,),dic) : 生成cls这个类对象,里面是有东西的
# 元类中
# __init__:控制类的产生, 在__new__之后
# __call__: 控制对象的产生
# __new__ : 控制类产生最根上,其实本质最根上也不是它,是type的__call__,但是我们控制不了

class Mymeta(type):
    def __init__(self, name, bases, dic):
        #self是Person类,Person类中有名称空间之类的了
        print(name)
        print(bases)
        print(dic)
        pass
    def __new__(cls, name, bases, dic):
        #产生空对象(空类),在这里面生成的并不是空类,是有数据的类了
        #如何完成类的初始化,并且把name, basea,dic这些东西放入
        #return type.__new__(cls,name, bases,dic)
        dic2={'attr':{}}
        for k,v in dic.items():
            if not k.startswith('__'):
                dic2['attr'][k]=v
        return type.__new__(cls,name, bases,dic2)
class Person(metaclass=Mymeta):
    school='oldboy'
    age=18
    def __init__(self,name,age):
        self.name=name
        self.age=age
print(Person.__dict__)
print(Person.attr['school']) #oldboy

单例

实现单例的四种模式

# #第一种方式(通过类的绑定方法)
# class sql():
#     _instance=None
#     def __init__(self, port, host):
#         self.port=port
#         self.host=host
#     @classmethod
#     def get_sigoleton(cls):
#         import settings
#         if not cls._instance:
#             cls._instance = cls(settings.PORT, settings.HOST)
#         return cls._instance
# s1=sql.get_sigoleton()
# s2=sql.get_sigoleton()
# print(s1)# <__main__.sql object at 0x00000000026A5FD0>
# print(s2)#<__main__.sql object at 0x00000000026A5FD0>
# s3=sql('33306','192.168.1.1')
# print(s3)

# #第二种方法:通过装饰器
# 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
# class sql():
#     def __init__(self,port,host):
#         self.port=port
#         self.host=host
# s1=sql()
# s2=sql()
# print(s1)
# print(s2)
# s3=sql('33306','192.168.1.1')
# print(s3)

# # 第三种方式:通过元类
# class Mymeta(type):
#     def __init__(self, name,bases, dic):
#         import settings
#         self._instance=self(settings.PORT,settings.HOST)
#     def __call__(self, *args, **kwargs):
#         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):
#     def __init__(self, port, host):
#         self.port=port
#         self.host=host
#
# s1=sql()
# s2=sql()
# print(s1)
# print(s2)
# s3=sql('33306','192.168.1.1')
# print(s3)

# 第四种方式(通过模块导入)
def test():
    from sigonleton import s1
    #print(s1.port)
    print(s1)
def test2():
    from sigonleton import s1 as s2
    print(s2)

test()
test2()
from sigonleton import s1
from sigonleton import sql
s2=sql('3306','192.168.1.1')
print(s1)
print(s2)