山东省高中信息技术学业水平考试试题网 - 数据与计算|信息系统与社会|数据与数据结构|网络基础|数据管理与分析|移动应用设计|三维设计与创意|开源硬件项目设计|算法初步|智能系统初步

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 175|回复: 6
收起左侧

Python_类和对象的创建过程(元类,__new__,__init__,__call__)

[复制链接]

1067

主题

1067

帖子

214748万

积分

超级版主

Rank: 8Rank: 8

积分
2147483647
发表于 2020-11-20 08:48:24 | 显示全部楼层 |阅读模式
欢迎各位小哥哥小姐姐阅读本<小生>的文章,对大家学习有帮助,请点赞加关注哦!!!!!!!!!!

您的点赞和关注将是我持续更新的动力呢.^v^

有不懂的问题可以私聊我哦!

一、 type()

1、创建类的两种方式

方式一



我们创建了一个名为MyClass的类,并实例化了这个类,得到其对象myc

上面代码打印的结果为:



type()函数可以查看一个类型或变量的类型,MyClass是一个class,它的类型就是type,而myc是一个实例,它的类型就是class MyClass。

我们说class的定义是运转时动态创建的,而创建class的方法就是运用type()函数。

type()函数既可以返回一个对象的类型,又可以创建出新的类型,比如,我们可以经过type()函数创建出MyClass类,而无需经过Class MyClass(object)...的定义:

方式二

动态创建类

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))



打印结果:



要创建一个class对象,type()函数依次传入3个参数:

class的名称;

继承的父类集合,留意Python支持多重继承,如果只需一个父类,别忘了tuple的单元素写法;

class的方法名称与函数绑定,这里我们把函数fn绑定到方法名func上。

经过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。

type就是创建类对象的类。你可以经过检查__class__属性来看到这一点。Python中所有的东西,留意,我是指所有的东西——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,并且它们都是从一个类(元类,默以为type,也可以自定制)创建而来。type也是由type创建。。



二、元类(metaclass)

除了运用type()动态创建类以外,要控制类的创建行为,还可以运用metaclass。

metaclass,直译为元类,简单的解释就是:

当我们定义了类以后,就可以依据这个类创建出实例,所以:先定义类,然后创建实例。

但是如果我们想创建出类呢?那就必需依据metaclass创建出类,所以:先定义元类(不自定义时,默许用type),然后创建类。

连接起来就是:先定义metaclass,就可以创建类,最后创建实例。

所以,metaclass允许你创建类或者修正类。换句话说,你可以把类看成是元类创建出来的“实例”。

默许情况下,类是运用type()构造的。类主体在一个新的名称空间中执行,类名在本地绑定到类型的结果(名称、基、名称空间)。

可以经过在类定义行中传送元类关键字参数来定制类创建过程,或者从包含此类参数的现有类继承。在下面的示例中,MyClass和MySubclass都是Meta的实例:



运用metaclass的两种方式



方式一:即用类的形式

执行代码后,当遇到class Foo时即声明要创建一个Foo类,就会调用type的__init__方法创建类,由于此处(metaclass=MyType),即指定了Foo类的创建方式,所以会执行type的派生类MyType的__init__方法,创建Foo类,打印一次'xx'

*一般情况下, 如果你要用类来实现metaclass的话,该类需要继承于type,并且通常会重写type的__new__方法来控制创建过程。

* 在metaclass里面定义的方法会成为类的方法,可以直接经过类名来调用



方式二:用函数的形式

构建一个函数,返回一个type的派生类对象,例如叫type的派生类, 需要3个参数:name, bases, attrs
    name: 类的名字bases: 基类,通常是tuple类型attrs: dict类型,就是类的属性或者函数

metaclass 原理

1.基础

metaclass的原理其实是这样的:当定义好类之后,创建类的时候其实是调用了type的__new__方法为这个类分配内存空间,创建好了之后再调用type的__init__方法初始化(做一些赋值等)。所以metaclass的所有magic其实就在于这个__new__方法里面了。

说说这个方法:__new__(cls, name, bases, attrs)

cls: 将要创建的类,相似与self,但是self指向的是instance,而这里cls指向的是class

name: 类的名字,也就是我们通常用类名.__name__获取的。

bases: 基类

attrs: 属性的dict。dict的内容可以是变量(类属性),也可以是函数(类方法)。

所以在创建类的过程,我们可以在这个函数里面修正name,bases,attrs的值来自由的达到我们的功能。这里常用的配合方法是

getattr和setattr(just an advice)



2.查找顺序

元类是由以下优先规则决定的:

如果“元类”存在,它就被运用了。

否则,如果至少有一个基类,则运用它的元类(这首先查找类属性,如果没有找到,则运用它的类型)。

否则,如果一个名为元类的全局变量存在,就会运用它。

三、 __init__,__new__,__call__三个特殊方法

__new__: 对象的创建,是一个静态方法,第一个参数是cls。(想想也是,不行能是self,对象还没创建,哪来的self)

其必需要有返回值,返回实例化出来的实例,需要留意的是,可以return父类__new__()出来的实例,也可以直接将object的__new__()出来的实例返回。

__init__ : 对象的初始化, 是一个实例方法,第一个参数是self,该self参数就是__new__()返回的实例,__init__()在__new__()的基础上可以完成一些其它初始化的动作,__init__()不需要返回值。

__call__ : 对象可call,留意不是类,是对象。

1.关于__new__




打印结果为:

<__main__.Bar object at 0x0090F930>

可以看到,输出来是一个Bar对象。

__new__方法在类定义中不是必需写的,如果没定义,默许会调用object.__new__去创建一个对象。如果定义了,就是会覆盖,运用自定义的,这样就可以自定制创建对象的行为。

单例模式也可以经过这种方式来创建。

2.关于__init__




打印结果:



__init__ 方法通常用在初始化一个类实例的时候,但__init__其实不是实例化一个类的时候第一个被调用 的方法。当运用 Persion(name, age) 这样的表达式来实例化一个类时,最先被调用的方法 其实是 __new__ 方法。从打印结果就可以看出来

若__new__()没有正确返回当前类cls的实例,那__init__()将不会被调用,即使是父类的实例也不行。

3.关于__call__

对象经过提供__call__(slef, *args ,**kwargs)方法可以模拟函数的行为,如果一个对象x提供了该方法,就可以像函数一样运用它,也就是说x(arg1, arg2...) 等同于调用x.__call__(self, arg1, arg2)



4、实例化对象的完好过程




当我们写如这段代码时,Python做了如下的操作:

Foo中有metaclass这个属性吗?如果是,Python会在内存中经过metaclass创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思绪)。如果Python没有找到metaclass,它会继续在Bar(父类)中寻觅metaclass属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到metaclass,它就会在模块层次中去寻觅metaclass,并尝试做同样的操作。如果还是找不到metaclass,Python就会用内置的type来创建这个类对象。

把上面这段话重复读几次,现在的问题就是,你可以在metaclass中放置些什么代码呢?

答案就是:可以创建一个类的东西。

那么什么可以用来创建一个类呢?

type,或者任何运用到type或者子类化type的东东都可以。

以上面的代码为例,我们实例化一个对象obj=Foo()时,会先执行Foo类的__new__方法,没写时,用父类的__new__方法,创建一个对象,并返回,然后执行__init__方法(自己有就用自己的,没有就用父类的),对创建的对象进行初始化。



obj()会执行Foo类的__call__方法,没有则用父类的

我们现在已经知道,类也是对象,是元类的对象,即我们实例化一个类时,调用其元类的__call__方法。

元类处置过程:定义一个类时,运用声明或者默许的元类对该类进行创建,对元类求type运算,得到父元类(该类声明的元类的父元类),调用父元类的__call__函数,在父元类的__call__函数中, 调用该类声明的元类的__new__函数来创建对象(该函数需要返回一个对象(指类)实例),然后再调用该元类的__init__初始化该对象(此处对象是指类,因为是元类创建的对象),最终返回该类

1.对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法

2.类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
原始type的__call__应该是参数结构应该是:  metaname, clsname, baseclasses, attrs 原始type的__new__  metaname, clsname, baseclasses, attrs 原始type的__init__  class_obj, clsname, baseclasses, attrs 元类的__new__和__init__影响的是创建类对象的行为,父元类的__call__控制对子元类的 __new__,__init__的调用,就是说控制类对象的创建和初始化。父元类的__new__和__init__由更上层的控制,    一般来说,原始type是最初的父元类,其__new__和__init__是具有普遍意义的,即应该是分配内存、初始化相关信息等元类__call__影响的是创建类的实例对象的行为,此时如果类自定义了__new__和__init__就可以控制类的对象实例的创建和初始化 __new__和__init__ 影响的是创建对象的行为,当这些函数在元类中时,影响创建的是类;同理,当这俩个函数在普通类中时,影响创建的是普通的对象实例。__call__ 影响()调用行为, __call__是在创建类的时候调用,即: class Test(object): __metaclass__=type, 定义类时就是创建类,此时会调用元类的__call__,如果元类有继承,子元类定义时执行的是父元类的__call__。 如果是普通类实例化对象,调用的是普通类的__call__
最后多说一句,小编是一名python开发工程师,这里有我自己整理了一套最新的python系统学习教程,包括从基础的python脚本到web开发、爬虫、数据分析、数据可视化、机器学习等。想要这些资料的可以关注小编,并在后台私信小编:“01”即可领取。


潍坊行知学校复读报名系统 已经正式上线,是集高考复读报名及查询,费用(学费、住宿费、资料费)核算,校园全景VR浏览,课堂教学实录体验,人工智能客服答疑于一体的一站式服务平台。潍坊行知学校教务处王老师竭诚为你服务,不尽事宜,致电王老师13854441151,微信7X24小时在线13854441151。潍坊行知学校复读咨询,潍坊行知学校复读报名系统,潍坊行知学校复读招生预报名系统,潍坊行知学校,潍坊行知学校复读,潍坊行知学校复读收费,潍坊行知学校复读收费标准,潍坊行知学校复读生收费标准,潍坊行知学校复读报名,潍坊行知学校复读报名时间,潍坊行知学复读招生,潍坊行知学校复读生,潍坊行知学校复读班,潍坊行知学校复读招生分数要求,潍坊行知学校复读招生简章。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
楼主热帖
+1
181°C
6
  • admin
  • admin
  • admin
  • admin
  • admin
过: 他们

帖子地址: 

回复

使用道具 举报

2333

主题

9355

帖子

214748万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2147483647
QQ
发表于 2020-11-20 08:48:36 | 显示全部楼层
转发了
回复 支持 反对

使用道具 举报

2333

主题

9355

帖子

214748万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2147483647
QQ
发表于 2020-11-20 08:48:46 | 显示全部楼层
转发了
回复 支持 反对

使用道具 举报

2333

主题

9355

帖子

214748万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2147483647
QQ
发表于 2020-11-20 08:48:57 | 显示全部楼层
转发了
回复 支持 反对

使用道具 举报

2333

主题

9355

帖子

214748万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2147483647
QQ
发表于 2020-11-20 08:49:04 | 显示全部楼层
转发了
回复 支持 反对

使用道具 举报

2333

主题

9355

帖子

214748万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2147483647
QQ
发表于 2020-11-20 08:49:15 | 显示全部楼层
转发了
回复 支持 反对

使用道具 举报

2333

主题

9355

帖子

214748万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2147483647
QQ
发表于 2020-11-20 08:49:23 | 显示全部楼层
转发了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

百度一下 百度二下 百度三下 开门大吉

QQ|Archiver|手机版|小黑屋|山东省高中信息技术学业水平考试试题网 ( 鲁ICP备16049757号-1 )|网站地图

GMT+8, 2021-2-28 22:55 , Processed in 0.363171 second(s), 34 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表