class Person: def __init__(self,name): self.name=name def score(self): print('分数是100') p=Person('nick') a=Person p=a('xichen') print(p.name)
print(type(p))
<class 'main.Person'>python
print(type(Person)) print(type(dict)) print(type(list)) print(type(str)) print(type(object)) print(type(type))
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>函数
在这里咱们发现,咱们打印出来的结果都显示type是产生dict、list、str、的元类code
**由此能够知道type是全部类的元类,而且type是继承object的类对象
class 类名,会把类构造出来blog
其实是:class 底层就是调用type来实例化产生类(对象),须要传一堆参数。只不过class关键字帮咱们干了这个事情继承
type(object_or_name, bases, dict)
字符串
object_or_name:类的名字,是个字符串
bases:是它的全部父类,基类
dict:名称空间,是一个字典get
def __init__(self,name) self.name = name Person = type('Person',(object,),{'age':'18','__init__':__init__}) print(Person.__dict__)
{'school': 'oldboy', 'init': <function init at 0x00000273833A1E18>, 'module': 'main', 'dict': <attribute 'dict' of 'Person' objects>, 'weakref': <attribute 'weakref' of 'Person' objects>, 'doc': None}
(<class 'object'>,)it
在这里咱们能够看到咱们打印Person这个类的父类的时候,咱们发现它是继承的是object类,虽然它是用type元类实例化出来的类,这就进一步说明了type在实例化类对象的时候,实际上是继承object的原理io
l={} exec(''' school='oldboy' def __init__(self,name): self.name=name def score(self): print('分数是100') ''',{},l) def __init__(self,name): self.name=name Person=type('Person',(object,),l) print(Person.__dict__)
{'school': 'oldboy', 'init': <function init at 0x000001B15A301E18>, 'score': <function score at 0x000001B15C175620>, 'module': 'main', 'dict': <attribute 'dict' of 'Person' objects>, 'weakref': <attribute 'weakref' of 'Person' objects>, 'doc': None}
print(Person.__bases__)
(<class 'object'>,)
p=Person('xichen') print(p.name)
xichen
print(p.__dict__)
{'name': 'xichen'}
自定义元类控制类的产生:能够控制类名,能够控制类的继承父类,控制类的名称空间
自定义元类必须继承type,若是一个类继承type, 这种类都叫元类
先写元类,在经过元类去控制类的产生,要在类继承的括号中写上metaclass=元类名
表示使用的元类
class Mymeta(type): # def __init__(self,*args,**kwargs): # 正常写法,可是咱们已经知道type传递的三个参数的意义 def __init__(self,name,bases,dic): # self 就是Person类 print(name) # 建立的类名 print(bases) # 继承的全部父类 print(dic) # 类中属性,是一个字典 #加限制 控制类名:必须以sb开头 if not name.startswith('sb'): raise Exception('类名没有以sb开头') #类必须加注释 print(self.__dict__['__doc__']) doc=self.__dict__['__doc__'] if not doc: #没有加注释 raise Exception('你的类没有加注释') #metaclass=Mymeta 指定这个类生成的时候,用本身写的Mymeta这个元类 class Person(object,metaclass=Mymeta): age='18' def __init__(self,name): self.name=name def score(self): print('分数是100') p=Person("xichen")
Person
(<class 'object'>,)
{'module': 'main', 'qualname': 'Person', 'doc': '\n 注释\n ', 'age': '18', 'init': <function Person.__init__ at 0x000001B97FDF19D8>, 'score': <function Person.score at 0x000001B97FDF1A60>}
Exception: 类名没有以sb开头
控制类的调用过程,实际上在控制:对象的产生 __call__
以前的内容说过,__call__
当对象加括号就会调用它。那么如今放到类对象也一样适用。
但只是说过类名()
实例化会先去调用init绑定方法,如今又说call是否是很混乱。
实际上,类名()实例化是先去调用call方法,再去调用init方法
如:
class Mymeta(type): def __call__(self, *args, **kwargs): print('xxx') return 1 class Person(object,metaclass=Mymeta): age='18' def __init__(self,name): self.name=name def score(self): print('分数是100') #先触发元类的__call__,再触发init的执行 p=Person('xichen') # 当类对象加括号实际上就是去调用了自定义元类中的__call__方法 print(p) # 因此p等于1 # print(p.name) # 没有返回对象,p等于1因此必定会报错
那么,若是像上面那样,不就得不到实例化对象了嘛?
实际上,实例化建立对象是经过call方法中的new方法。这些call方法,new方法,init都是一些魔法方法
可是new方法只会获得一个新的对象,什么都没有的对象。
但咱们实例化获得对象的本事是为了共享类中属性和方法,须要绑定上属性和方法。这时候就须要再使用init方法
如:
class Mymeta(type): def __call__(self, *args, **kwargs): # self 就是Person类 print(2) print(self.mro()) # 类对象的属性查找顺序 # obj=self.__new__(self) # 方法1,经过self的new方法建立对象 obj=object.__new__(self) # 方法2,经过object的new方法建立对象 obj.__init__(*args, **kwargs) # 调用对象的init方法 return obj def __init__(self,*args): print(3) print(args) class Person(metaclass=Mymeta): # 其实是先调用元类的call方法,再回调自定义元类的init方法 age = '18' def __init__(self, name): # 当类实例化生成对象后,会经过call调用init方法 print(1) self.name = name p = Person(name='xichen') # 先调用自定义元类的call方法 print(p.__dict__) print(p.name) print(p)
3
('Person', (), {'module': 'main', 'qualname': 'Person', 'age': '18', 'init': <function Person.__init__ at 0x0000012BFC236A60>})
2
[<class 'main.Person'>, <class 'object'>]
1
{'name': 'xichen'}
xichen
<main.Person object at 0x0000012BF53229B0>