一、概述

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

二、类的起源

  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. Centos7下安装Oracle11g r2

    我的centos7是在virtualbox下安装的,安装Oracle安装了好久好久,最开始的时候在网上找的两个文章,按照步骤装,有一篇写着装的时候有灰色的竖线,直接按space键或者鼠标右键close ...

  2. I understand that you would like to know about the Amazon Giveaway

    Dear Seller, Greetings from Amazon Seller Support. From your mail, I understand that you would like ...

  3. centos上搭建git服务--3

    前言:当我们想要实现几个小伙伴合作开发同一个项目,或者建立一个资源分享平台的时候,GIT就是一个很好的选择.当然,既然是一个共有平台,那么把这个平台放到个人计算机上明显是不合适的,因此就要在服务器上搭 ...

  4. 作业要求20181113-4 Beta阶段第1周/共2周 Scrum立会报告+燃尽图 02

    作业要求:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2384 版本控制:[https://git.coding.net/lglr201 ...

  5. 2017年软件工程第八次作业-互评Alpha版本

    B.Thunder——爱阅app(测评人:方铭) 一.基于NABCD评论作品,及改进建议 每个小组评论其他小组Alpha发布的作品:1.根据(不限于)NABCD评论作品的选题:2.评论作品对选题的实现 ...

  6. 安装VS的过程

    软件工程学习到第三周,我们需要下载一个新的软件,用来进行软件测试.刚开始知道的时候觉得没甚么,不就是下个软件吗!有什么大不了的,分分钟搞定的事.可是想象很美好,现实很骨感.这是一个巨大的工作量呀,不仅 ...

  7. WebService(三)

    JAX-WS简单使用示例: 1.服务端 package com.rong.service; import javax.jws.WebMethod; import javax.jws.WebParam; ...

  8. 定时器应用-点击按钮,div向右移动

    需求是点击button,div就一直往右移动,给个条件left=800px就停止移动,通过定时器来控制. 代码如下: <!DOCTYPE html> <html> <he ...

  9. python3.6 SSL module is not available

    pip is configured with locations that require TLS/SSL, however the ssl module in Python is not avail ...

  10. Spring-MVC理解之二:前置控制器

    原文链接:http://www.cnblogs.com/brolanda/p/4265749.html 一.前置控制器配置与讲解 上篇中理解了IOC容器的初始化时机,并理解了webApplicatio ...