同样效果的代码:
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 = name
self.age = age
def tell(self):
print('%s 的年龄是:%s'%(self.name,self.age))
当然,我们可以通过第二种方式创建类:
#!/usr/bin/python
-- coding:utf-8 --
country = ‘China’
def init(self,name,age):
self.name = name
self.age = age
def 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):
pass
country = ‘China’
def init(self,name,age):
self.name = name
self.age = age
def 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):
pass
class Person(object,metaclass=MyMetaClass): #自定义元类,来创建类.
country = ‘China’
def init(self,name,age):
self.name = name
self.age = age
def 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 obj
def __init__(self, name, age):
"""创建完实例对象之后,才会调用__init__."""
print(self)
print('------------init----------')
self.name = name
self.age = age
student = 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(’’):
continue
if not callable(value):
continue
if 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 = name
self.age = age
def 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(’__’):
continue
if not callable(value):
continue
if 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 obj
class Person(object,metaclass=MyMetaClass): #这一行: Person = MyMetaClass(‘Person’,(object,),{…})
“”"
元类.
“”"
country = ‘China’
def __init__(self,name,age):
self.name = name
self.age = age
def 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(’__’):
continue
if not callable(value):
continue
if 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 obj
def __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 = name
self.age = age
def 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 obj
def __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 = name
self.age = age
def 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 = name
self.age = age
def __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):
pass
class Person(object, metaclass=MyMetaClass): # 这一行: Person = MyMetaClass(‘Person’,(object,),{…})
country = 'China'
def __init__(self, name, age):
print('-----Person--init-----')
self.name = name
self.age = age
def 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 666
class Person(object, metaclass=MyMetaClass): # 这一行: Person = MyMetaClass(‘Person’,(object,),{…})
country = 'China'
def __init__(self, name, age):
print('-----Person--init-----')
self.name = name
self.age = age
def 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’>
666
Process 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__产生一个空对象obj
obj = cls.new(cls)
print(obj)
print(obj.dict) #此时名称空间为空.
#调用__init__初始化这个对象.
cls.init(obj,*args,**kwargs)
#返回初始化的对象
print(obj.dict)
return obj
class Person(object, metaclass=MyMetaClass): # 这一行: Person = MyMetaClass(‘Person’,(object,),{…})
country = 'China'
def __init__(self, name, age):
print('-----Person--init-----')
self.name = name
self.age = age
def 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 obj
class Student(object,metaclass=MyMeta):
country = ‘China’
def __init__(self,name,age):
self.name = name
self.age = age
def 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 25
Process 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):
"""这个类没有什么用."""
pass
def __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 obj
class Student(object,metaclass=MyMetaClass):
country = 'China'
langage = 'Chinese'
def __init__(aa,name,age):
aa.name = name
aa.age = age
def __teach(self):
pass
student = 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 obj
class Student(object,metaclass=MyMeta): #Student = MyMeta(‘Student’,(object,),{…})
def init(self,name,age):
self.name = name
self.age = age
def 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] = value
else:
cls_new_dict[key.upper()] = value
cls_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 = 35
def __init__(self,name,age):
print(self)
print(self.__dict__)
self.name = name
self.age = age
def 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] = value
else:
cls_dict_new[key.upper()] = value
for 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 = 35
def __init__(self,name,age):
print(self)
print(self.__dict__)
self.name = name
self.age = age
def 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 None
Process 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(’__’):
pass
else:
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 = 35
def __init__(self,name,age):
self.name = name
self.age = age
def 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()]=v
return obj
class 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()