类的起源与metaclass
一、概述
我们知道类可以实例化出对象,那么类本身又是怎么产生的呢?我们就来追溯一下类的起源。
二、类的起源
2.1 创建一个类
class Foo(object): def __init__(self, name):
self.name = name f = Foo('bigberg') # 我们创建一个 Foo的类
# 实例化一个 对象 f
在python中有个说法:一切皆为对象。如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
print(type(f))
print(type(Foo)) # 输出 <class '__main__.Foo'>
<class 'type'> # 对象 f 由类 Foo创建
# Foo类由 type 创建
所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
2.2 type 创建类
type创建类的格式,类名 = type('类名',(父类,),{'方法名':方法的内存地址})
def func(self): # 定义一个函数
print('hello,world') Foo = type('Foo', (object,), {'talk': func}) # type创建类,(object,) 为元组 f = Foo()
f.talk()
print(type(f))
print(type(Foo)) # 输出
hello,world
<class '__main__.Foo'>
<class 'type'
可以看到type 确实可以创建一个类,并且可以实例化对象
那么我们如何传参呢?就需要我们自己写构造函数这些了:
def func(self):
print('hello,%s' % self.name) def __init__(self, name): # 构造函数
self.name = name Foo = type('Foo', (object,), {'talk': func, '__init__': __init__}) f = Foo('Bigberg') # 传参
f.talk() # 输出
hello,Bigberg
So: 类 是由 type 类 实例化产生的
三、__new__方法
__new__() 是在新式类中新出现的方法,它作用在构造方法建造实例之前,可以这么理解,在 Python 中存在于类里面的构造方法 __init__() 负责将类的实例化,而在 __init__() 启动之前,__new__() 决定是否要使用该 __init__() 方法,因为__new__() 可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。
class Foo(object): def __init__(self, name):
self.name = name
print("in the Foo __init__") def __new__(cls, *args, **kwargs): # 第一个参数cls,是当前正在实例化的类,这里是object
print("Foo __new__", cls, *args, ** kwargs)
return object.__new__(cls) # 继承父类的__new__方法 f = Foo('bigberg')
print(f.name) # 输出 Foo __new__ <class '__main__.Foo'> bigberg # new方法先于init方法执行
in the Foo __init__
bigberg
__new__() 方法的特性:
- __new__() 方法是在类准备将自身实例化时调用。
- __new__() 方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
注意:
事实上如果(新式)类中没有重写__new__()方法,即在定义新式类时没有重新定义__new__()时,Python默认是调用该类的直接父类的__new__()方法来构造该类的实例,如果该类的父类也没有重写__new__(),那么将一直按此规矩追溯至object的__new__()方法,因为object是所有新式类的基类。
如果我们不返回__new__()方法,无法进行实例化对象
class Foo(object): def __init__(self, name):
self.name = name
print("in the Foo __init__") def __new__(cls, *args, **kwargs): object
print("Foo __new__", cls, *args, ** kwargs)
# return object.__new__(cls)
f = Foo('bigberg')
print(f.name)
# 输出
File "G:/python/untitled/study6/类的起源.py", line 39, in <module>
print(f.name)
AttributeError: 'NoneType' object has no attribute 'name'
四、__metaclass__方法
4.1 metaclass作用
metaclass这个属性叫做元类,它是用来表示这个类是由谁来帮他实例化创建的,说白了,就是相当于自己定制一个类,就这么一个意思。
class MyType(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)
return obj def __new__(cls, *args, **kwargs):
print("Mytype __new__", *args, **kwargs)
return type.__new__(cls, *args, **kwargs) print('here...') class Foo(object, metaclass=MyType): def __init__(self, name):
self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs):
print("Foo __new__", cls, *args, **kwargs)
return object.__new__(cls) f = Foo("Bigberg")
print("f", f)
print("fname", f.name) #输出 here...
Mytype __new__ Foo (<class 'object'>,) {'__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x000002A1968FE8C8>, '__module__': '__main__', '__new__': <function Foo.__new__ at 0x000002A1968FE950>}
Mytype __init__ Foo (<class 'object'>,) {'__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x000002A1968FE8C8>, '__module__': '__main__', '__new__': <function Foo.__new__ at 0x000002A1968FE950>}
Mytype __call__ Bigberg
Foo __new__ <class '__main__.Foo'>
obj <__main__.Foo object at 0x000002A196905898> Bigberg
<class '__main__.Foo'>
Foo __init__
f <__main__.Foo object at 0x000002A196905898>
fname Bigberg
创建过程如下:
4.2 执行顺序
类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__
类的起源与metaclass的更多相关文章
- 面向对象【day08】:类的起源与metaclass(二)
本节内容 1.概述 2.类的起源 3.__new__方法 4.__metaclass__方法 一.概述 前面我们学习了大篇幅的关于类,通过类创建对象,那我们想知道这个类到底是怎么产生的呢?它的一切来源 ...
- python元类:type和metaclass
python元类:type和metaclass python中一切皆对象,所以类本身也是对象.类有创建对象的能力,那谁来创建类的呢?答案是type. 1.用tpye函数创建一个类 class A(ob ...
- 类的特殊成员方法,类的起源type, metaclass
1.__doc__表示类的描述信息 2. __module__ 和 __class__ __module__ 表示当前操作的对象在那个模块 __class__ 表示当前操作的对象的类是什么 ...
- python基础-类的起源
Python中一切事物都是对象. class Foo(object): def __init__(self,name): self.name = name f = Foo("alex&quo ...
- python 描述符 上下文管理协议 类装饰器 property metaclass
1.描述符 #!/usr/bin/python env # coding=utf-8 # 数据描述符__get__ __set__ __delete__ ''' 描述符总结 描述符是可以实现大部分py ...
- 探索未知种族之osg类生物---起源
任何程序都是有生命的,是生命就需要呼吸.例如普通的windows程序,当运行完main()函数后,就需要进入消息循环,来监听用户的各种操作,以便做出及时的回应.这样的每次循环就像生命的每次呼吸,来维持 ...
- **类的起源--type
通过type类的实例化,创建新的类. #!/usr/bin/env python # Version = 3.5.2 def func(self): print('Hello,{}'.format(s ...
- Python类(八)-类的起源
首先用type()看一下类和实例化对象的类型 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" class Person(obj ...
- python笔记-9(subprocess模块、面向对象、socket入门)
一.subprocess 模块 1.了解os.system()与os.popen的区别及不足 1.1 os.system()可以执行系统指令,将结果直接输出到屏幕,同时可以将指令是否执行成功的状态赋值 ...
随机推荐
- POWERDESIGNER生成的代码有引号
昨天在用powerdesigner画的一个导入ORACLE中.发现都带了双引号, 当时没在意,以为是分隔符.那想后要在ORACLE查询表是一定要输入双引号才能查询.. 后来才知道而这在oracle 中 ...
- eclipse 简单操作
1.设置字体: windows --> preferences --> general --> Colors and Fonts --> Basic --> 双击 Tex ...
- 对字符串进行base64加解密---基于python
本文介绍Python 2.7中的base64模块,该模块提供了基于rfc3548的Base16, 32, 64编解码的接口.官方文档,参考这里. 当前接口基于rfc3548的Base16/32/64编 ...
- 查看dll依赖项
win7 系统: 开始-->所有程序->vs2012文件夹->vs tools->对应的命令提示符 输入命令: dumpbin /dependents 你的文件(可以是exe, ...
- Python:集合操作总结
集合是一组无序排列的不重复元素集 [注]:集合的最大作用是对一个序列进行去重操作 一.集合的分类 在Python中集合分为两类,为可变集合(set)和不可变集合(frozenset).对于可变集合(s ...
- (Miller Rabin算法)判断一个数是否为素数
1.约定 x%y为x取模y,即x除以y所得的余数,当x<y时,x%y=x,所有取模的运算对象都为整数. x^y表示x的y次方.乘方运算的优先级高于乘除和取模,加减的优先级最低. 见到x^y/z这 ...
- WebService(二)
使用eclipse开发webservice的服务器端以及客户端的简单实例 1.服务端 在eclipse中像建立一个web项目一样,new->Dynamic Web Project A.建一个需要 ...
- 【beta】Scrum站立会议第6次....11.8
小组名称:nice! 组长:李权 成员:于淼 刘芳芳韩媛媛 宫丽君 项目内容:约跑app(约吧) 时间:2016.11.8 12:00——12:30 地点:传媒西楼220室 本次对beta阶段 ...
- sleep() 与 wait()的比较
1.这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类. sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还 ...
- IE8 没有内容的盒子,如果有定位,浮现在其他盒子上 可能会有点击穿透没有作用的情况
IE8 没有内容的盒子,如果有定位,浮现在其他盒子上 可能会有点击穿透没有作用的情况