元类(一切皆对象)以及深浅拷贝

元类

元类的来源是:python中一切皆对象。

什么是元类

元类就是用来实例化产生类的类

关系:元类---实例化---类(自定义的类)---实例化----对象(obj)

如何查看内置的元类

1.type是内置的元类
2.我们用class关键字定义出来的所有类以及内置的类都是由内置的元类type实例化产生的

例如:在python中int、dict内置元类都继承自object类,int和dict又都是type元类的对象

print(type(int))  # <class 'type'>

print(type(dict)) # <class 'type'>

那么type和object又是什么关系呢?我们来type一下object和type!

print(type(type))  #<class 'type'>

print(type(object)) #<class 'type'>

其实:

1.object的元类其实是type类,object是由type类构造出来的对象
2.type是自己的对象(指针指向了自己)
3.type类又继承了object类

class机制分析(class如何造出类的)

calss其实底层执行了以下四个步骤,造出了类!

class Func:

    def put(self):

        print('正在执行上传功能')

    def __del__(self):

        print('run...')

# 1.得到类名

class_name = 'Func'



# 2.得到类的基类

class_bases = (object,)



# 3.执行类体代码拿到名称空间!

class_dict = {}

class_body = """

def put(self):

    print('正在执行上传功能')

def __del__(self):

    print('run...')

"""

# exec第一个参数是类体代码、第二个是类体代码中的全局变量、第三的是一个空字典容器

exec (class_body,{},class_dict)

print(class_dict)



# 4.调用元类,得到People类

Func = type(class_name,class_bases,class_dict)

print(Func)



# Func类就是type元类实例化产生出来的对象!!!!

如何自定义元类来控制类的产生

在3.3中,我们是使用type元类控制Func类的产生。其实,我们也可以自定义元类来控制类产生

class MyMeta(type):   # 只有继承了type的类才是元类

    def __init__(self,x,y,z): # 注意调用MyMeta这个类其实传入了四个参数分别是self、class_name,class_bases,class_dict

        print('run...')

        print(x) # x对应class_name

        print(y) # y对应class_bases

        print(z) # z对应class_dict



class Func(metaclass=MyMeta):

    def put(self):

        print('正在执行上传功能')

    def __del__(self):

        print('run...')



# 在自定义类的时候,metaclass默认等于type,我们可以通过指定metaclass=MyMeta来自定义元类

# 指定了metaclass=MyMeta,其实就执行了第四步调用元类Func = MyMeta(class_name,class_bases,class_dict)

# 调用MyMeta(class_name,class_bases,class_dict)发生了三件事!

# 注意!!!调用它就等于调用了type的__call__方法!!!!

#     1.先造一个空对象---Func--这里其实先调用了MyMeta类里的__new__()方法

#     2.调用MyMeta这个类的__init__方法,完成初始化对象操作

#     3.返回初始化好的对象



"""

完成上述操作之后,我们就可以在自定义的MyMeta元类里面的init方法里面,规定一下类的产生必须满足那些条件!

"""

元类下的属性查找

首先,切记!!父类不是元类!!

对象.属性查找是先从自己那找,再到类中,再到该类的父类中,最后到object类

类.属性查找是先从该类的父类中找,再到父类的父类中找,再到object中找,最后还要到该类的元类中找

一切皆对象的好处

它可以通过一切皆对象,使得任何类型的变量值能够赋值给变量!
因为,其本质是变量都指向了一个内存地址,而并不是直接指向具体的数据(在其他语言中不能这样)

image

深浅拷贝

1.赋值,本质是多了一个变量指向另一个变量的内存地址

l = [11,22,[311,444,55]]

l2 = l # 赋值操作,本质就是l2指向了l的内存地址

print(l2 is l) # 结果为true

image

2.浅拷贝,本质是又拷贝一份内存地址指向对应的变量值

from copy import copy

l = [111,222,[333,444]]

l3 = copy(l) # 浅拷贝,只是拷贝了l的内存地址

print(l3 is l) # 结果为false

# 修改l3的列表值,l也会改变!

image

3.深拷贝:本质内存地址、值全部拷贝一份,非常占内存!

from copy import deepcopy



l = [111,222,[333,444]]

l4 = deepcopy(l)

print(l4 is l) # 结果为false

# 深拷贝是把内存地址、变量值全部拷贝了一份,所以修改l4中列表的值,l并不会改变

# 注意:深拷贝,拷贝的时候l列表里面的不可变类型地址并不会改变,改变的是可变类型的地址!!
posted @ 2022-08-30 10:44  等日落  阅读(100)  评论(0编辑  收藏  举报