元类回顾
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)