一、概述

  我们知道类可以实例化出对象,那么类本身又是怎么产生的呢?我们就来追溯一下类的起源。

二、类的起源

  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的更多相关文章

  1. 面向对象【day08】:类的起源与metaclass(二)

    本节内容 1.概述 2.类的起源 3.__new__方法 4.__metaclass__方法 一.概述 前面我们学习了大篇幅的关于类,通过类创建对象,那我们想知道这个类到底是怎么产生的呢?它的一切来源 ...

  2. python元类:type和metaclass

    python元类:type和metaclass python中一切皆对象,所以类本身也是对象.类有创建对象的能力,那谁来创建类的呢?答案是type. 1.用tpye函数创建一个类 class A(ob ...

  3. 类的特殊成员方法,类的起源type, metaclass

    1.__doc__表示类的描述信息 2. __module__ 和  __class__  __module__ 表示当前操作的对象在那个模块 __class__     表示当前操作的对象的类是什么 ...

  4. python基础-类的起源

    Python中一切事物都是对象. class Foo(object): def __init__(self,name): self.name = name f = Foo("alex&quo ...

  5. python 描述符 上下文管理协议 类装饰器 property metaclass

    1.描述符 #!/usr/bin/python env # coding=utf-8 # 数据描述符__get__ __set__ __delete__ ''' 描述符总结 描述符是可以实现大部分py ...

  6. 探索未知种族之osg类生物---起源

    任何程序都是有生命的,是生命就需要呼吸.例如普通的windows程序,当运行完main()函数后,就需要进入消息循环,来监听用户的各种操作,以便做出及时的回应.这样的每次循环就像生命的每次呼吸,来维持 ...

  7. **类的起源--type

    通过type类的实例化,创建新的类. #!/usr/bin/env python # Version = 3.5.2 def func(self): print('Hello,{}'.format(s ...

  8. Python类(八)-类的起源

    首先用type()看一下类和实例化对象的类型 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" class Person(obj ...

  9. python笔记-9(subprocess模块、面向对象、socket入门)

    一.subprocess 模块 1.了解os.system()与os.popen的区别及不足 1.1 os.system()可以执行系统指令,将结果直接输出到屏幕,同时可以将指令是否执行成功的状态赋值 ...

随机推荐

  1. 如何更改Arcmap里经纬度小数点后面的位数?

    customize>arcmap option>data view >round coordinate to 改成想要显示的小数位数

  2. activemq 持久化

    转自: http://blog.csdn.net/kobejayandy/article/details/50736479 消息持久性的原理很简单,就是在发送者将消息发送出去后,消息中心首先将消息存储 ...

  3. python3【基础】-集合

    集合( set):把不同的元素组成一起形成集合,是python基本的数据类型. 集合元素(set elements):组成集合的成员(不可重复) class set(object) | set() - ...

  4. 20181009-3 Scrum立会报告+燃尽图02

    此作业要求:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2190] 一.小组介绍 组长:王一可 组员:范靖旋,王硕,赵佳璐,范洪达,祁 ...

  5. C++:const用法的简单总结

    一.对变量的修饰 在c++中,如果我们希望定义一个值不会被改变的变量,那么可以用关键字const对它进行修饰,被修饰后的变量其作用相当于一个常量 //这两种方式等价 2 语法1:const 类型名 变 ...

  6. 软工1816 · Alpha冲刺(5/10)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 后端代码复审 福大各个食堂的菜品口味量化.属性标记 组织前后端线下协作 接下来 ...

  7. Oracle判断字段中是否包含中文(若有,取出该中文的方法)

    一.问题说明 在处理数据的时候,需要判断某个字段字符串中是否有中文,若有则取出中文. 二.解决办法 首先如何判断某个字段字符串中是否有中文.这里介绍三种方法: 1.采用ASCIISTR函数 说明:AS ...

  8. babel-preset-env: a preset that configures Babel for you

    转载 babel-preset-env is a new preset that lets you specify an environment and automatically enables t ...

  9. Delphi编程防止界面卡死的方法经验分享

    Delphi编程防止界面卡死的方法经验分享! 1.循环里面防止界面卡死的方法可以使用Application.ProcessMessages:  例如下列方法:    var      n: Integ ...

  10. EL语法 ${person.id} 这里面的id指的是实例对象的成员变量

    EL语法 ${person.id} 这里面的id指的是实例对象的成员变量