menu
more_vert
面向对象【day08】:类的特殊成员-类的起源与metaclass

作者:dayu

1
2
3
4
5
6
7
8
9
10
11
classDog(object):
"""此类是形容Dog这个类"""#类的描述信息

def__init__(self,name):
self.name=name


print(Dog.__doc__)#打印类的描述信息

#输出
此类是形容Dog这个类




2 __module__和__class__

说明:

  1. __module__: 表示当前操作的对象在哪个模块
  2. __class__:表示当前操作的对象的类是什么

技术分享

aa.py的代码:

1
2
3
4
classC(object):

def__init__(self):
self.name="shuaigaogao"




index.py的代码:

1
2
3
4
5
6
7
8
9
10
fromlib.aaimportC

obj=C()

print(obj.__module__)#表示当前操作的对象在哪个模块
print(obj.__class__)#表示当前操作的对象的类是什么

#输出
lib.aa
<class‘lib.aa.C‘>




3__init__

说明:构造方法,通过类创建对象时,自动触发执行

4 __del__

说明:析构方法,当对象在内存中被释放时,自动触发执行

1
2
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,
所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的




5__call__

说明:对象后面加括号,触发执行

1
2
3
4
5
6
7
8
9
10
11
12
classFoo(object):
def__init__(self):
self.name="shuaigaogao"

def__call__(self,*args,**kwargs):#重写call方法
print("running call",args,kwargs)

f=Foo()#执行__init__
f(1,2,3,name=333)# 执行call方法,也可以写成 Foo()(1,2,3,name=333)

#输出
running call (1,2,3) {‘name‘:333}




注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

6 __dict__

说明:查看类或对象中的所有成员

①类.__dict__

效果:打印类中所有的属性,不包括实例属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
classProvince(object):

country=‘China‘

def__init__(self, name, count):
self.name=name
self.count=count

deffunc(self,*args,**kwargs):
print("func")

print(Province.__dict__)#类.__dict__

#输出
{‘__doc__‘:None,‘__weakref__‘: <attribute‘__weakref__‘of‘Province‘objects>,‘__init__‘:
<function Province.__init__ at0x00000247F3CAD488>,‘country‘:‘China‘,‘__dict__‘:
<attribute‘__dict__‘of‘Province‘objects>,‘func‘: <function Province.func at
0x00000247F3CAD510>,‘__module__‘:‘__main__‘}#打印类中所有的属性,不包括实例属性




②实例名.__dict__

效果:打印该实例的所有属性,不包括类属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
classProvince(object):

country=‘China‘

def__init__(self, name, count):
self.name=name
self.count=count

deffunc(self,*args,**kwargs):
print("func")

p=Province("jiangsu",20000)#实例化
print(p.__dict__)#实例名.__dict__

#输出
{‘count‘:20000,‘name‘:‘jiangsu‘}#打印该实例的所有属性,不包括类属性




7 __str__

说明:如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
classProvince(object):

country=‘China‘

def__init__(self, name):
self.name=name

def__str__(self):
return"<obj:{0}>".format(self.name)

p=Province("jiangsu")
print(p)#打印这个对象

#输出
<obj:jiangsu>#给对象重新起了一个名字




注:这个以后会在django框架里面会用到,这边就不多说了

8 __getitem__、__setitem__、__delitem__

说明:用于索引操作,如字典。以上分别表示获取、设置、删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
classFoo(object):

def__getitem__(self, key):
print(‘__getitem__:‘,key)

def__setitem__(self, key, value):
print(‘__setitem__:‘,key,value)

def__delitem__(self, key):
print(‘__delitem__‘,key)


f=Foo()
f["name"]="shuaigaogao"#自动触发__setitem__方法
f["name"]#自动触发__getitem__方法
delf["name"]#自动触发__delitem__方法

#输出
__setitem__: name shuaigaogao
__getitem__: name
__delitem__ name




注:这边的__delitem__没有做真正的删除,只是触发这个方法,想要真正删除,只需要在__delitem__函数中添加删除功能即可

二、类的起源于metaclass

一、概述

  前面我们学习了大篇幅的关于类,通过类创建对象,那我们想知道这个类到底是怎么产生的呢?它的一切来源是什么?还有对象,对象是通过什么方法创建的,现在我们一头雾水,行的,下面我们就来揭开类的面纱,看看类和对象到底是怎么创建的,通过什么创建的。

二、类的起源

2.1 传统创建类

1
2
3
4
5
classFoo(object):
def__init__(self,name):
self.name=name

f=Foo("shuaigaogao")




f 是通过 Foo 类实例化的对象,其实,不仅 f 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象,按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

1
2
print(type(f))#输出:<class ‘__main__.Foo‘> 表示:f 对象由Foo类创建
print(type(Foo))#输出:<class ‘type‘> 表示:Foo类对象由 type 类创建




所以,f对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建

2.2 type创建类

说明: type创建类的格式,类名 = type(‘类名‘,(父类,),{‘方法名‘:方法的内存地址})

1
2
3
4
5
6
7
8
9
10
11
12
13
deffunc(self):#创建方法
print("hello {0}".format(self.name))

def__init__(self,name):#创建构造方法
self.name=name

#通过type创建类,如果是经典类的话则写成:Foo = type("Foo",(),{"talk":func,"__init__":__init__})
Foo=type("Foo",(object,),{"talk":func,"__init__":__init__})
f=Foo("shuaigaogao")#创建对象
f.talk()

#输出
hello shuaigaogao




总结:类是由type 类实例化产生的

值得注意的是,新式类的写法,在继承父类那边,你继承一个父类后面就要加一个逗号,加逗号,它就把它当做一个元组,不加逗号,就是一个值了

技术分享

三、__new__方法

3.1 概念

new方法是类自带的一个方法,可以重构,__new__方法在实例化的时候也会执行,并且先于__init__方法之前执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
classFoo(object):

def__init__(self,name):
self.name=name

print("Foo __init__")

def__new__(cls,*args,**kwargs):
print("Foo __new__",cls,*args,**kwargs)
returnobject.__new__(cls)

f=Foo("shuaigaogao")

#输出
Foo __new__ <class‘__main__.Foo‘> shuaigaogao#执行了new方法
Foo __init__#执行了__init__方法




3.2 new方法作用

作用:所有对象都是通过new方法来实例化的,new里面调用了init方法,所以在实例化的过程中先执行的是new方法,而不是init方法。

①重构__new__方法

1
2
3
4
5
6
7
8
9
10
11
12
13
classFoo(object):

def__init__(self,name):
self.name=name
print("Foo __init__")

def__new__(cls,*args,**kwargs):
print("Foo __new__",cls,*args,**kwargs)

f=Foo("shuaigaogao")#实例化

#输出
Foo __new__ <class‘__main__.Foo‘> shuaigaogao




由上面的例子看出,没有执行__init__方法

②重构__new__方法,并继承父类的__new__方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
classFoo(object):

def__init__(self,name):
self.name=name

print("Foo __init__")

def__new__(cls,*args,**kwargs):#cls相当于传入类Foo
print("Foo __new__",cls,*args,**kwargs)
returnobject.__new__(cls)#继承父类的__new__方法,这边必须以返回值的形式继承

f=Foo("shuaigaogao")

#输出
Foo __new__ <class‘__main__.Foo‘> shuaigaogao
Foo __init__




由上面不难看出,大多数情况下,你都不要去重构你的__new__方法,因为你父类中已经有__new__方法了,已经帮你写好了怎么去创建类,如果你重写的话,就会覆盖父类的里面的__new__方法。但是你重构可以增加一点小功能,但是你覆盖了以后还是需要继承父类回来,要不然你的这个实力就创建不了。

3.3 使用场景

我想对我自己写的一些类进行定制,就在它实例化之前就进行定制,就可以用到__new__方法,new方法就是用来创建实力的,重构new方法,必须以返回值的形式继承父类的new方法。

①需求:我在创建对象时候,同时创建一个类变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classFoo(object):

def__init__(self,name):
self.name=name

print("Foo __init__")

def__new__(cls,*args,**kwargs):#cls相当于是传入的类名Foo
cls.name="shuaigaogao"#创建对象是定义静态变量
print(cls.name)
returnobject.__new__(cls)#继承父类的__new__方法

f=Foo("shuaigaogao")
print(Foo.name)

#输出
shuaigaogao
Foo __init__
shuaigaogao




四、__metaclass__方法

4.1 metaclass作用

metaclass这个属性叫做元类,它是用来表示这个类是由谁来帮他实例化创建的,说白了,就是相当于自己定制一个类,就这么一个意思。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
classMyType(type):
def__init__(self,*args,**kwargs):

print("Mytype __init__",*args,**kwargs)

def__call__(self,*args,**kwargs):
print("Mytype __call__",*args,**kwargs)
obj=self.__new__(self)
print("obj ",obj,*args,**kwargs)
print(self)
self.__init__(obj,*args,**kwargs)
returnobj

def__new__(cls,*args,**kwargs):
print("Mytype __new__",*args,**kwargs)
returntype.__new__(cls,*args,**kwargs)

classFoo(object,metaclass=MyType):#python3统一用这种
#__metaclass__ = MyType #python2.7中的写法

def__init__(self,name):
self.name=name

print("Foo __init__")

def__new__(cls,*args,**kwargs):
print("Foo __new__",cls,*args,**kwargs)
returnobject.__new__(cls)

f=Foo("shuaigaogao")
print("f",f)
print("fname",f.name)

#输出
Mytype __new__ Foo (<class‘object‘>,) {‘__new__‘: <function Foo.__new__ at0x0000025EF0EFD6A8>,
‘__init__‘: <function Foo.__init__ at0x0000025EF0EFD620>,‘__qualname__‘:‘Foo‘,‘__module__‘:‘__main__‘}
Mytype __init__ Foo (<class‘object‘>,) {‘__new__‘: <function Foo.__new__ at0x0000025EF0EFD6A8>,
‘__init__‘: <function Foo.__init__ at0x0000025EF0EFD620>,‘__qualname__‘:‘Foo‘,‘__module__‘:‘__main__‘}
Mytype __call__ shuaigaogao
Foo __new__ <class‘__main__.Foo‘>
obj <__main__.Fooobjectat0x0000025EF0F05048> shuaigaogao
<class‘__main__.Foo‘>
Foo __init__
f <__main__.Fooobjectat0x0000025EF0F05048>
fname shuaigaogao




创建过程如下:

技术分享

4.2 执行顺序

类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__

metaclass 详解文章:猛击这里得票最高那个答案写的非常好

面向对象【day08】:类的特殊成员-类的起源与metaclass

原文地址:http://www.cnblogs.com/luoahong/p/7208395.html