同样效果的代码:

    def __init__(cls,cls_name,cls_bases,cls_dict):type.__init__(cls,cls_name,cls_bases,cls_dict)def __new__(cls, cls_name, cls_bases,cls_dict):return type.__new__(cls,cls_name,cls_bases,cls_dict)def __call__(self, *args, **kwargs):return type.__call__(self,*args,**kwargs)

创造对象的方法:obj = object.__new__(cls)

Python内置函数参考:

http://www.runoob.com/python/python-built-in-functions.html 

https://www.cnblogs.com/coder2012/p/4309999.html

https://www.cnblogs.com/elie/p/6685429.html

https://blog.csdn.net/yugongpeng_blog/article/details/45868909

@在一个类的内部,__new__当中的第一个参数cls就是所在类的类的名字,__init__当中的第一个参数self就是所在类创建的对象的名

字,__call__当中的第一个参数self就是所在类创建的对象的名字。

2018年8月6日19:30:09

刚一接触面向对象元类的时候,我就懵逼了,真的,那是一种无助的懵逼。

当然,我们需要先理清一下思路,先看看什么是元类:


在Python当中万物皆对象,我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类,元类可以简称为类的类,

元类的主要目的是为了控制类的创建行为.

type是Python的一个内建元类,用来直接控制生成类,在python当中任何class定义的类其实都是type类实例化的结果。

只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类,自定义元类可以控制类的产生过程,类的产生过程其实就是元类

的调用过程.


看到这,你明白了点没,没错,我们每天看到的class XXX这个XXX就是由元类实例化产生的,在Python当中,创建一个类其实有两种方

式,这个让我想起了Scala.

一个类由三大组成部分,分别是

1、类名class_name

2、继承关系class_bases

3、类的名称空间class_dict

方式1:使用class关键字(python解释器转化为第二种)

方式2:通过type关键字,依次传入以上三个参数即可。

听到这里,你先别蒙圈,我们正常定义类是这样写的:

class Person(object):country = 'China'def __init__(self,name,age):self.name = nameself.age = agedef tell(self):print('%s 的年龄是:%s'%(self.name,self.age))

当然,我们可以通过第二种方式创建类:

#!/usr/bin/python
# -*- coding:utf-8 -*-country = 'China'
def __init__(self,name,age):self.name = nameself.age = agedef tell(self):print('%s 的年龄是:%s'%(self.name,self.age))Person = type('Person',(object,),{'country':country,'__init__':__init__,'tell':tell})print(Person.__dict__)
person = Person('wtt',25)
print(person.__dict__)

OK,大家看到了吧,Person类实际上就是一个类对象,于是我们将产生类的类称之为元类,默认的元类是type.

默认情况下,我们所说的元类都是指type这个元类,但是用户是可以自定义元类的,只要继承type就可以,如下所示:

#!/usr/bin/python
# -*- coding:utf-8 -*-class MyMetaClass(type):passcountry = 'China'
def __init__(self,name,age):self.name = nameself.age = agedef tell(self):print('%s 的年龄是:%s'%(self.name,self.age))Person = MyMetaClass('Person',(object,),{'country':country,'__init__':__init__,'tell':tell})print(Person.__dict__)
person = Person('wtt',25)
print(person.__dict__)

当然,我们也可以用这种日常的形式:

#!/usr/bin/python
# -*- coding:utf-8 -*-class MyMetaClass(type):passclass Person(object,metaclass=MyMetaClass): #自定义元类,来创建类.country = 'China'def __init__(self,name,age):self.name = nameself.age = agedef tell(self):print('%s 的年龄是:%s'%(self.name,self.age))print(Person.__dict__)
person = Person('wtt',25)
print(person.__dict__)

到现在为止,对于元类稍微了解了,为了能够顺利讲下去,我们先介绍一个__new__这个方法,之所以要讲这个,是因为我和你一样:

我开始的时候以为Python当中__init__方法就是Java当中的构造方法,其实不是这样子的,在Python当中,当我们实例化一个对象的时

候,最先调用的并不是__init__方法,而是这个__new__方法

代码示例:

#!/usr/bin/python
# -*- coding:utf-8 -*-class Student(object):def __new__(cls, *args, **kwargs):"""这个相当于Java当中的构造函数"""print(cls)   #注意:第一个参数就是类本身print('---------new--------------')obj = super().__new__(cls)print(obj)print(obj.__dict__)return objdef __init__(self, name, age):"""创建完实例对象之后,才会调用__init__."""print(self)print('------------init----------')self.name = nameself.age = agestudent = Student('wtt',30)

运行结果示例:

<class '__main__.Student'>
---------new--------------
<__main__.Student object at 0x00000000021C9C88>
{}
<__main__.Student object at 0x00000000021C9C88>
------------init----------Process finished with exit code 0

正如代码所示:__new__创造出了对象,但是这个对象是空的,名称空间的装备需要通过__init__来完成。

之前我已经介绍过了,元类的主要目的是为了为了控制类的创建行为,但是到现在还没有见到元类到底有什么高逼格的用途!!,不要着

急,我们先来一个实例场景:

要求:利用元类的知识,保证用户设计的类必须有文档注释,不能为空 ,同时要求在一个类内部定义的所有函数必须有文档注释,不能为

空。

#!/usr/bin/python
# -*- coding:utf-8 -*-"""利用元类:第一:类必须有文档注释,不能为空 第二:在一个类内部定义的所有函数必须有文档注释,不能为空.(这个很通用)"""# !/usr/bin/python
# -*- coding:utf-8 -*-"""利用元类:第一:类必须有文档注释,不能为空 第二:在一个类内部定义的所有函数必须有文档注释,不能为空.(这个很通用)"""class MyMetaClass(type):def __init__(self, cls_name, cls_bases, cls_dict):print(self)    #<class '__main__.Person'>"""注意:self.__dict__传进来的时候类的名称空间不是空的."""print(self.__dict__) #{'__init__': <function Person.__init__ at 0x0000000002946268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Person' objects>, 'tell_info': <function Person.tell_info at 0x00000000029462F0>, 'country': 'China', '__doc__': '\n    元类.\n    ', '__dict__': <attribute '__dict__' of 'Person' objects>}if '__doc__' not in cls_dict or len(cls_dict['__doc__'].strip()) == 0:raise TypeError('类:%s 必须有文档注释,并且注释不能为空.' % cls_name)for key, value in cls_dict.items():if key.startswith('__'):continueif not callable(value):continueif not value.__doc__ or len(value.__doc__.strip()) == 0:raise TypeError('函数:%s 必须有文档注释,并且文档注释不能为空.' % (key))super().__init__(cls_name, cls_bases, cls_dict)  # 重用父类的功能.class Person(object, metaclass=MyMetaClass):  # 这一行: Person = MyMetaClass('Person',(object,),{...})"""元类."""country = 'China'def __init__(self, name, age):self.name = nameself.age = agedef tell_info(self):"""绑定方法."""print('%s 的年龄是:%s' % (self.name, self.age))

因为刚才我们已经介绍了__init__和__new__的区别了,所以我们也可以在__new__当中直接做手脚.

#!/usr/bin/python
# -*- coding:utf-8 -*-"""利用元类:第一:类必须有文档注释,不能为空 第二:在一个类内部定义的所有函数必须有文档注释,不能为空.(这个很通用)"""class MyMetaClass(type):def __new__(cls, cls_name, cls_bases, cls_dict):print(cls)  #注意:<class '__main__.MyMetaClass'>if '__doc__' not in cls_dict or len(cls_dict['__doc__'].strip()) == 0:raise TypeError('类:%s 必须有文档注释,并且注释不能为空.' % cls_name)for key, value in cls_dict.items():if key.startswith('__'):continueif not callable(value):continueif not value.__doc__ or len(value.__doc__.strip()) == 0:raise TypeError('函数:%s 必须有文档注释,并且文档注释不能为空.' % (key))obj =  super().__new__(cls,cls_name,cls_bases,cls_dict)print(obj)  #<class '__main__.Person'>  创建出来的就是Person类,是我们需要的.return objclass Person(object,metaclass=MyMetaClass):  #这一行: Person = MyMetaClass('Person',(object,),{...})"""元类."""country = 'China'def __init__(self,name,age):self.name = nameself.age = agedef tell_info(self):"""绑定方法."""print('%s 的年龄是:%s'%(self.name,self.age))

OK,到这里你是否懂了呢,还不懂,OK,那我在写一步,你肯定会懂的。

#!/usr/bin/python
# -*- coding:utf-8 -*-"""利用元类:第一:类必须有文档注释,不能为空 第二:在一个类内部定义的所有函数必须有文档注释,不能为空.(这个很通用)"""class MyMetaClass(type):def __new__(cls, cls_name, cls_bases, cls_dict):print(cls)  #注意:<class '__main__.MyMetaClass'>if '__doc__' not in cls_dict or len(cls_dict['__doc__'].strip()) == 0:raise TypeError('类:%s 必须有文档注释,并且注释不能为空.' % cls_name)for key, value in cls_dict.items():if key.startswith('__'):continueif not callable(value):continueif not value.__doc__ or len(value.__doc__.strip()) == 0:raise TypeError('函数:%s 必须有文档注释,并且文档注释不能为空.' % (key))obj =  super().__new__(cls,cls_name,cls_bases,cls_dict)print(obj)  #<class '__main__.Person'>  创建出来的就是Person类,是我们需要的.print('--------名称空间------')print(obj.__dict__)return objdef __init__(self,cls_name, cls_bases, cls_dict):print(self)   #<class '__main__.Person'>#接下来我们初始化这个对象super().__init__(cls_name,cls_bases,cls_dict)class Person(object,metaclass=MyMetaClass):  #这一行: Person = MyMetaClass('Person',(object,),{...})"""元类."""country = 'China'def __init__(self,name,age):self.name = nameself.age = agedef tell_info(self):"""绑定方法."""print('%s 的年龄是:%s'%(self.name,self.age))

但是有个地方我不是太懂,为什么在__new__中打印出来的名称空间不是空的呢??,现在能想到的就是继承的类是type导致的,而且在最

开始__init__打印的时候也是这个样子的。

其实核心就是下面这个图:

简化版:

#!/usr/bin/python
# -*- coding:utf-8 -*-class MyMeta(type):n = '测试'def __new__(cls, *args, **kwargs):print(cls)   #<class '__main__.MyMeta'>obj = super().__new__(cls,*args,**kwargs)print(obj.__dict__)#{'__weakref__': <attribute '__weakref__' of 'Student' objects>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__init__': <function Student.__init__ at 0x00000000025162F0>, 'country': 'China', '__module__': '__main__', '__doc__': None, 'say': <function Student.say at 0x0000000002516378>}print(obj)#<class '__main__.Student'>return objdef __init__(self,class_name,class_bases,class_dic):print(self) #<class '__main__.Student'>super().__init__(class_name,class_bases,class_dic)class Student(object,metaclass=MyMeta):  #Student = MyMeta('Student',(object,),{....})country = 'China'def __init__(self,name,age):self.name = nameself.age = agedef say(self):print('%s 的年龄是:%s'%(self.name,self.age))

上面我们讲的这些可以用几句话来进行概括:元类对类创建行为的影响。 

接下来我们要讲的是元类对类实例化行为的影响。

但是在讲之前,我们需要介绍一下__call__,不然没法写下去了。


内置函数__call__的用法:

一个可调用的对象加括号,就是触发这个对象所在的类中的__call__方法的执行,一个对象可以加括号意味着产生这

个对象对应的类里面肯定含有__call__方法,

反之要想让某个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法。


是不是有点听不懂,不要着急,举个例子:

#!/usr/bin/python
# -*- coding:utf-8 -*-class Student(object):def __init__(self,name,age):self.name = nameself.age = agedef __call__(self, *args, **kwargs):print(args)print(kwargs)student = Student('wtt',25)
"""如果没有__call__:TypeError: 'Student' object is not callable"""
print(callable(student))
student(10,20,30,40)  #一个可调用的对象加括号,就是触发这个对象所在类中的__call__方法的执行.

总之一句话:一个可调用的对象加括号,就是触发这个对象所在类中的__call__方法的执行.

在这里我们可以细想一下,由元类造出的这些类之所以可以加上()被调用,肯定是因为元类当中也存在着__call__方法,OK,先上一个

例子在说。

#!/usr/bin/python
# -*- coding:utf-8 -*-class MyMetaClass(type):passclass Person(object, metaclass=MyMetaClass):  # 这一行: Person = MyMetaClass('Person',(object,),{...})country = 'China'def __init__(self, name, age):print('-----Person--init-----')self.name = nameself.age = agedef tell_info(self):print('%s 的年龄是:%s' % (self.name, self.age))print(callable(Person))
person = Person('wtt',25)   #Person这个类之所以可以被调用,肯定是因为造出Person的类:MyMetaClass当中含有__call__方法.
print(person.__dict__)

在上面的例子当中,我们来重写一下MyMetaClass当中__call__方法,你会发现一个很有意思的事情。

#!/usr/bin/python
# -*- coding:utf-8 -*-class MyMetaClass(type):def __call__(cls, *args, **kwargs):print(cls)return 666class Person(object, metaclass=MyMetaClass):  # 这一行: Person = MyMetaClass('Person',(object,),{...})country = 'China'def __init__(self, name, age):print('-----Person--init-----')self.name = nameself.age = agedef tell_info(self):print('%s 的年龄是:%s' % (self.name, self.age))print(callable(Person))
person = Person('wtt',25)   #Person这个类之所以可以被调用,肯定是因为造出Person的类:MyMetaClass当中含有__call__方法.
print(person)

运行结果:

True
<class '__main__.Person'>
666Process finished with exit code 0

OK,你是不是已经发现了什么,没错:

一个可调用的对象加上()的返回值就是这个对象所在类中的__call__方法的返回值.

到这里,你可能会懵逼,我去,说好的Person对象呢,怎么返回一个666呢,到这里就将到了重点:


在Python当中,简述__call__,__new__,__init__三者之间的关系

在类实例化的过程当中,哪个对象加()就寻找产生这个对象的类的__call__方法,只要是__call__方法,一定会做三件事情:

第一:调用__new__方法,构造新的对象,相当于Java当中的构造函数.(对象自己的__new__)

第二:调用__init__方法,去初始化这个对象(对象自己的__init__)

第三:返回这个对象.

注意:__new__更像是其他语言当中的构造函数,必须有返回值,返回值实例化的对象,__init__只是初始化构造函数,必须没有返回

值,仅仅只是初始化功能,并不能new创建对象.

也就是说,一个类在实例化的时候实际上是做了三件事情:

第一:触发元类中(造出这个类的类)的__call__方法

第二:通过__new__产生一个空对象

第三:通过__init__初始化这个对象

第四:返回这个对象


OK,到这里我写一个完整的例子你就彻底懂了。

#!/usr/bin/python
# -*- coding:utf-8 -*-class MyMetaClass(type):def __call__(cls, *args, **kwargs):print('--自动触发元类当中的__call__方法---')#调用__new__产生一个空对象objobj = cls.__new__(cls)print(obj)print(obj.__dict__)   #此时名称空间为空.#调用__init__初始化这个对象.cls.__init__(obj,*args,**kwargs)#返回初始化的对象print(obj.__dict__)return objclass Person(object, metaclass=MyMetaClass):  # 这一行: Person = MyMetaClass('Person',(object,),{...})country = 'China'def __init__(self, name, age):print('-----Person--init-----')self.name = nameself.age = agedef tell_info(self):print('%s 的年龄是:%s' % (self.name, self.age))def __new__(cls, *args, **kwargs):print('---------new--------')return super().__new__(cls)print(callable(Person))
person = Person('wtt',25)   #Person这个类之所以可以被调用,肯定是因为造出Person的类:MyMetaClass当中含有__call__方法.
print(person)

运行结果:

True
--自动触发元类当中的__call__方法---
---------new--------
<__main__.Person object at 0x0000000001F6D390>
{}
-----Person--init-----
{'name': 'wtt', 'age': 25}
<__main__.Person object at 0x0000000001F6D390>Process finished with exit code 0  

老铁,我在给你导入一张图片:

从图片上面我们是不是理解了很多了呢?类在实例化对象的时候函数的调用顺序依次是__call__==>__new__==>__init__.

到这里你是否感觉元类很高级:既可以控制创建类的行为,也可以控制类的实例化行为。

但是这么牛逼的功能有什么用途呢,不着急,咱么接着先举一个例子试一试:

要求:利用元类,在元类中控制自定义的类产生的对象的相关的属性全部为隐藏属性

#!/usr/bin/python
# -*- coding:utf-8 -*-"""利用元类:将一个对象的所有属性都变成私有的"""class MyMeta(type):def __call__(cls, *args, **kwargs):obj = cls.__new__(cls,*args,**kwargs)cls.__init__(obj,*args,**kwargs)#这个对象本来构造并初始化完毕了,但是我们不立即进行返回,而是进行进一步的操作:obj.__dict__ = {'_%s__%s'%(cls.__name__,key):value for key,value in obj.__dict__.items()}print(obj.__dict__)return objclass Student(object,metaclass=MyMeta):country = 'China'def __init__(self,name,age):self.name = nameself.age = agedef tell_info(self):print('%s的姓名是:%s'%(self.name,self.age))def __new__(cls, *args, **kwargs):return super().__new__(cls)student = Student('wtt',25)
print(student.__dict__)
print(student._Student__name,student._Student__age)

运行结果示例:

{'_Student__name': 'wtt', '_Student__age': 25}
{'_Student__name': 'wtt', '_Student__age': 25}
wtt 25Process finished with exit code 0

方法2:

#!/usr/bin/python
# -*- coding:utf-8 -*-class MyMetaClass(type):def __new__(cls,cls_name,cls_bases,cls_dict):return type.__new__(cls,cls_name,cls_bases,cls_dict)def __init__(cls,cls_name,cls_bases,cls_dict):"""这个类没有什么用."""passdef __call__(cls, *args, **kwargs):obj = cls.__new__(cls,*args,**kwargs)cls.__init__(obj,*args,**kwargs)obj_dict = obj.__dict__obj.__dict__ = {}for key,value in obj_dict.items():setattr(obj,'_%s__%s'%(cls.__name__,key),value)return objclass Student(object,metaclass=MyMetaClass):country = 'China'langage = 'Chinese'def __init__(aa,name,age):aa.name = nameaa.age = agedef __teach(self):passstudent = Student('wtt',35)
print(student.__dict__)

看着是不是很牛掰,现在我们稍微总结一下完整代码:

#!/usr/bin/python
# -*- coding:utf-8 -*-"""def __call__(cls, *args, **kwargs):obj = cls.__new__(cls,*args,**kwargs)cls.__init__(obj,*args,**kwargs)return obj"""class MyMeta(type):"""用来控制类的创建行为."""def __init__(self,cls_name,cls_bases,cls_dict):super().__init__(cls_name,cls_bases,cls_dict)def __new__(cls, *args,**kwargs):return super().__new__(cls,*args,**kwargs)"""用来控制类的实例化行为."""def __call__(cls, *args, **kwargs):obj = cls.__new__(cls,*args,**kwargs)cls.__init__(obj,*args,**kwargs)obj.__dict__ = { '_%s__%s'%(cls.__name__,key):value for key,value in obj.__dict__.items()}print(obj.__dict__)return objclass Student(object,metaclass=MyMeta):   #Student = MyMeta('Student',(object,),{...})def __init__(self,name,age):self.name = nameself.age = agedef tell(self):print('%s 的基本信息是:%s'%(self.name,self.age))def __new__(cls, *args, **kwargs):return super().__new__(cls)student = Student('wtt',25)

  

接下来我们上一个更牛X的例子,通过元类来实现单例模式,直接看我的博客吧。

https://www.cnblogs.com/zhangmingyang/p/9439882.html

到这里我们在可以总结一下__new__和__init__的关系:

官方文档是如此说明的

If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked.

当__new__函数没有返回这个类的实例时,__init__函数不会被调用,其实也容易理解,__init__需要类实例self参数,而__new__没有返

回一个类实例,这样的话__init__自然无法运行。

OK ,我们在来感受一下元类的强大:

要求:在元类中控制把自定义类的数据属性都变成大写。

代码示例:

#!/usr/bin/python
# -*- coding:utf-8 -*-"""在元类中控制把自定义类的数据属性都变成大写"""class MyMeta(type):def __new__(cls, cls_name,cls_bases,cls_dict):cls_new_dict = {}for key,value in cls_dict.items():if callable(value) or key.startswith('__'):cls_new_dict[key] = valueelse:cls_new_dict[key.upper()] = valuecls_new_dict['salary'] = '呵呵哒.'return super().__new__(cls,cls_name,cls_bases,cls_new_dict)def __init__(cls,cls_name,cls_bases,cls_dict):"""在这里你会发现cls即Student这个类(对象)的数据属性已经被初始化完了,看来元类的_new_比普通强大."""for key,value in cls.__dict__.items():print(key,value)"""cls_dict你会发现和我们想的不一样(应该等于cls_new_dict),看来元类不一样啊."""print('&'*60)print(cls_dict)super().__init__(cls_name,cls_bases,cls_dict)class Student(object,metaclass=MyMeta): #Student = MyMeta('Student',(object,),{...})country = 'China'age = 35def __init__(self,name,age):print(self)print(self.__dict__)self.name = nameself.age = agedef tell(self):print('%s 的姓名是:%s'%(self.name,self.age))print('-'*30)
for key,value in Student.__dict__.items():print(key,value)

运行结果:

salary 呵呵哒.
__module__ __main__
__doc__ None
tell <function Student.tell at 0x0000000002916378>
COUNTRY China
__weakref__ <attribute '__weakref__' of 'Student' objects>
__dict__ <attribute '__dict__' of 'Student' objects>
AGE 35
__init__ <function Student.__init__ at 0x00000000029162F0>Process finished with exit code 0

在这里我有一个疑问:本来我之前的代码是按照下面写的,但是没有生效:

#!/usr/bin/python
# -*- coding:utf-8 -*-"""在元类中控制把自定义类的数据属性都变成大写"""class MyMeta(type):def __init__(cls,cls_name,cls_bases,cls_dict):"""疑问1:cls作为一个对象竟然有属性了????"""cls_dict_new = {}for key,value in cls_dict.items():if callable(value) or key.startswith('__'):cls_dict_new[key] = valueelse:cls_dict_new[key.upper()] = valuefor key,value in cls_dict_new.items():print(key,value)cls_dict_new['salary'] = '呵呵哒'"""疑问2:修改完之后传进去没有生效.??"""super().__init__(cls_name,cls_bases,cls_dict)class Student(object,metaclass=MyMeta): #Student = MyMeta('Student',(object,),{...})country = 'China'age = 35def __init__(self,name,age):print(self)print(self.__dict__)self.name = nameself.age = agedef tell(self):print('%s 的姓名是:%s'%(self.name,self.age))print('-'*30)
for key,value in Student.__dict__.items():print(key,value)

运行结果:

__init__ <function Student.__init__ at 0x00000000021C6268>
__module__ __main__
COUNTRY China
AGE 35
__qualname__ Student
tell <function Student.tell at 0x00000000021C62F0>
------------------------------
age 35
__init__ <function Student.__init__ at 0x00000000021C6268>
country China
__module__ __main__
__dict__ <attribute '__dict__' of 'Student' objects>
__weakref__ <attribute '__weakref__' of 'Student' objects>
tell <function Student.tell at 0x00000000021C62F0>
__doc__ NoneProcess finished with exit code 0

我这里是这么猜测的,普通类的__new__用来创造空对象,__init__用来初始化对象,但是元类的__new__把这两个活都干了,__init__没有什么用!!!

后来没有办法,我采用了下面的方法:

#!/usr/bin/python
# -*- coding:utf-8 -*-"""在元类中控制把自定义类的数据属性都变成大写"""class MyMeta(type):def __init__(cls,cls_name,cls_bases,cls_dict):for key,value in cls.__dict__.items():if callable(value) or key.startswith('__'):passelse:key_new = key.upper()"""删除cls对应的属性值,不能用del"""delattr(cls,key)"""为cls属性值重新赋值,不能用cls."""setattr(cls,key_new,value)super().__init__(cls_name,cls_bases,cls_dict)class Student(object,metaclass=MyMeta): #Student = MyMeta('Student',(object,),{...})country = 'China'age = 35def __init__(self,name,age):self.name = nameself.age = agedef tell(self):print('%s 的姓名是:%s'%(self.name,self.age))for key,value in Student.__dict__.items():print(key,value)

运行结果:

__weakref__ <attribute '__weakref__' of 'Student' objects>
tell <function Student.tell at 0x00000000029162F0>
__init__ <function Student.__init__ at 0x0000000002916268>
__doc__ None
COUNTRY China
AGE 35
__dict__ <attribute '__dict__' of 'Student' objects>
__module__ __main__Process finished with exit code 0

最后在来一道题,装X技能: 

要求:

在元类中控制自定义的类无需__init__方法

1.元类帮其完成创建对象,以及初始化操作

2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument

3.key作为用户自定义类产生对象的属性,且所有属性变成大写

代码示例:呵呵,这这道题告诉我们,元类控制着根本啊,根本没用到__init__方法。

#!/usr/bin/python
# -*- coding:utf-8 -*-'''
在元类中控制自定义的类无需__init__方法
1.元类帮其完成创建对象,以及初始化操作
2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
3.key作为用户自定义类产生对象的属性,且所有属性变成大写
'''class MyMeta(type):def __call__(cls, *args, **kwargs):if args:raise  TypeError('must use keyword argument')obj = cls.__new__(cls,*args,**kwargs)for key,value in kwargs.items():setattr(obj,key.upper(),value)#obj.__dict__[key.upper()]=vreturn objclass Student(object,metaclass=MyMeta):def __new__(cls, *args, **kwargs):return super().__new__(cls)def tell(self):print('%s 的信息是:%s'%(self.NAME,self.AGE))student = Student(name='wtt',age=25)
student.tell()

  

深入理解Python元类(原创)相关推荐

  1. 深入理解python元类

    类和对象 什么是元类 __metaclass属性 定制元类 为什么要使用元类 总结 类和对象 在理解什么是元类之前,有必要先理解下,什么是类. 什么是类?通俗的讲,类就是用来创建对象的代码片.在pyt ...

  2. 理解Python元类——e-satis

    什么是元类?我们什么时候使用它? 翻译自StackOverflow:e-satis大神的回答 类也是对象 在理解元类之前,你需要掌握Python的类.Python从Smalltalk上借鉴了一个非常奇 ...

  3. 深入理解 python 元类

    一.什么的元类 # 思考: # Python 中对象是由实例化类得来的,那么类又是怎么得到的呢? # 疑问: # python 中一切皆对象,那么类是否也是对象?如果是,那么它又是那个类实例化而来的呢 ...

  4. python 元类工厂模式_Python进阶丨如何创建你的第一个Python元类?

    摘要:通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类. Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一. ...

  5. 如何创建你的第一个Python元类?

    Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一.通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类.本文介绍 ...

  6. Python进阶丨如何创建你的第一个Python元类?

    摘要:通过本文,将深入讨论Python元类,其属性,如何以及何时在Python中使用元类. Python元类设置类的行为和规则.元类有助于修改类的实例,并且相当复杂,是Python编程的高级功能之一. ...

  7. python元类_Python元类

    python元类 Welcome to today's tutorial on python metaclass. We all know that python is an object orien ...

  8. python元类_Python基础:元类

    一.概述 Python虽然是多范式的编程语言,但它的数据模型却是 纯面向对象 的.与那些仅在语法层面声称纯OO的编程语言(如Java)相比,Python的这种纯粹性更加深入骨髓. 在Python的世界 ...

  9. Python元类详解

    文章目录 Python元类详解 Python谜团 元类的本质 调用一个类时发生了什么 再探元类 自定义元类 彩蛋:跳过python解释器 Python元类详解 元类比99%的用户所担心的魔法要更深,如 ...

最新文章

  1. 宏基因组学揭示海洋微生物及其病毒的生态学
  2. 洛谷 P1055 ISBN号码【字符串+模拟】
  3. Codeforces 911F Tree Destruction
  4. 重温强化学习之无模型学习方法:TD(lambda)
  5. 开源在线机器学习Online Learning/Incremental Learning库-creme介绍
  6. Docker与虚拟机
  7. 文献记录(part2)--A Dykstra-like algorithm for two monotone operators
  8. 一个直角三角形的两个直角边是 a,b(a≤b),其斜边是 c,且 a,b,c都是正整数。现在我们已经知道了斜边长度c,请问这个直角三角形的两个直角边的长度是什么?Java
  9. 移动磁盘文件或目录损坏且无法读取资料如何找回
  10. ABP源码分析三十六:ABP.Web.Api
  11. javascript调用一个函数(对象),new和直接调用的区别
  12. android 选择多选图片
  13. (转)AIX rootvg 镜像创建与磁盘更换
  14. JQ6500语音模块
  15. FFT算法实现——python
  16. 人工智能与就业系列调研 | 老板电器的新蝶变
  17. 网络共享计算机权限访问,局域网共享时提示:你没有权限访问,请与网络管理员联系...
  18. js对象、数字深拷贝方式(转)
  19. 关于对齐次裁剪空间及HLSL语义的理解
  20. Seen and Unseen emotional style transfer for voice conversion with a new emotional speech dataset

热门文章

  1. 基于STM32的物联网监控小车
  2. Hfish蜜罐的搭建与测试
  3. 神经网络为何沉寂多年?一文体会深度学习的巨人之力——反向传播算法
  4. 看不懂idea的文档怎么办【安利一款idea翻译插件】
  5. 讲计算机知识的up主,电脑小常识:人人视频如何关注up主
  6. Spring中的若干设计模式
  7. 原生js html insert,原生js添加节点appendChild、insertBefore
  8. happy Mom ——php mysqli DES加密
  9. [FLEX笔记]网络监视器引起的Channel.Security.Error#2048
  10. 四阶亚当姆斯预报-校正系统