首页 > 编程语言 >Python基础之面向对象:8、面向对象之元类

Python基础之面向对象:8、面向对象之元类

时间:2022-11-08 17:34:28浏览次数:41  
标签:__ Python self 元类 面向对象 init print type 之元类

目录

面向对象之元类

一、什么是元类

  • Python中一切皆为对象,对象是有类实例化生成;
  • 类也是对象(类对象),生成类对象的类可称之为元类;
  • 所以,元类就是来创建类对象的,可称之为类工厂;
  • type是python内建元类,type是最上层的元类,也可称为一切类对象的元类

二、元类推导流程

"""推导步骤1:如何查看数据的数据类型"""
# s1 = 'hello world'  # str()
# l1 = [11, 22, 33, 44]  # list()
# d1 = {'name': 'jason', 'pwd': 123}  # dict()
# t1 = (11, 22, 33, 44)  # tuple()
# print(type(s1))  # <class 'str'>
# print(type(l1))  # <class 'list'>
# print(type(d1))  # <class 'dict'>
# print(type(t1))  # <class 'tuple'>

"""推导步骤2:其实type方法是用来查看产生对象的类名"""
# class Student:
#     pass
# obj = Student()
# print(type(obj))  # <class '__main__.Student'>

"""推导步骤3:python中一切皆对象 我们好奇type查看类名显示的是什么"""
class Student:
    pass
obj = Student()
print(type(obj))  # <class '__main__.Student'>
print(type(Student))  # <class 'type'>
class A:pass
class B:pass
print(type(A), type(B))

"""
结论:我们定义的类其实都是由type类产生的>>>:元类(产生类的类)
"""

三、创建类的方式

方式一:

创建方法:

​ 直接使用class关键字创建

class Foo:

    school_name = 'kangkang

    def func1(self):
        pass

    print(Teacher)
    print(Teacher.__dict__)

方式二:

创建方法:

​ 使用元类type

​ type(类名, 类的父类, 类的名称空间)

cls = type('Student', (object,), {'name':'jason'})
print(cls)
print(cls.__dict__)

"""
1.手动写键值对
    针对绑定方法不好定义
2.内置方法exec
    能够运行字符串类型的代码并产生名称空间
"""

四、元类定制类的产生行为

​ 通过上述推导,我们得出了我们所创建的类,其实就是type帮我们所生成的,那么我们是否可以通过继承type(元类)的方式,来研究type底层代码原理,来改修,新增条件,来定制类的生成

例如:

​ 生成类时,类名的首字母必须大写,否则报错

推导流程:

"""
推导
	1、对象是由类名加括号产生的  	__init__
	2、类是由元类加括号产生的		__init__
	3、查看type底层源码,找到__init__
        __init__(cls, what, bases=None, dict=None)
        cls:元类本身
        what:需要产生的类名
        bases:产生类的父类
        dict:类体名称空间
	4、通过上述我们就可以发现what可以控制类名的产生
	
"""

# 1、首先生成一个类,继承元类(type) 
    class MyMetaClass(type):
        pass
    
# 2、在类中,创建def __init__(self, what, bases=None, dict=None):
# 3、对限制what产生类名的条件
	class MyMetaClass(type):
        
    def __init__(self, what, bases=None, dict=None):
        
        # 设置条件,未满足时,主动抛出异常并提示
        if not what.istitle():
            raise TypeError('类的首字母要大写')
            
        # 条件满足后调用父类进行产生
        super().__init__(what, bases, dict)

# 4、指定类的元类:利用关键字metaclass指定类的元类
class myclass(metaclass=MyMetaClass):
    desc = '元类其实很有趣 就是有点绕'

class Student(metaclass=MyMetaClass):
    info = '我是学生 我很听话'
print(Student)
print(Student.__dict__)

# 5、这个时候我们在生成MyMetaClass的子类时,就必须要遵循它的条件,否则将会报错

五、元类定制对象的产生行为

要求:

​ 生成的对象必须使用关键字进行传参,否则将无法生成对象

推导流程:

'''
推导:
	1、我们在上述学习了类的魔法方法,发现:
	2、对象加括号会执行产生该对象类里的__call__
	3、类加括号会执行产生该类的类里的__call__
	4、观察__call__(self, *args, **kwargs):
		self: 调用者本身
		*args:接收位置实参
		**kwargs:接收关键字实参
	5、得出结论,我们需要对args进行约束就可达到条件
'''

class MyMetaClass(type):
    def __call__(self, *args, **kwargs):
        
        # 1.产生一个空对象(骨架)
        # 2.调用__init__给对象添加独有的数据(血肉)
        # 3.返回创建好的对象
        # print(args)  # ('jason', 18, 'male')
        # print(kwargs)  # {}
        
 		  # 设置条件
        if args:
        # 当条件未满足时,主动抛出异常,并提升
            raise TypeError("需要进行关键字传参")
            
        # 条件满足后执行,使用super,重新调用父类
        return super().__call__(*args, **kwargs)
    	


class Student(metaclass=MyMetaClass):
    def __init__(self, name, age, gender):
        # print('__init__')
        self.name = name
        self.age = age
        self.gender = gender


# obj = Student('jason', 18, 'male')
obj = Student(name='jason',age= 18,gender= 'male')
print(obj.__dict__)

六、元类之双下new

​ 当我们在使用类产生对象时,类体代码种名字产生的顺序是:

​ __ call __ >>>: __ new __ >>>:__ init __

​ 双下call将类名传给双下new,然后new将对象的名字传给双下init而后产生类名

​ 得出结论:对象是由new进行产生的

class MyMetaClass(type):
    def __call__(self, *args, **kwargs):
        
        # 1.产生一个空对象(骨架)
        obj = self.__new__(self)
        
        # 2.调用__init__给对象添加独有的数据(血肉)
        self.__init__(obj,*args, **kwargs)
        
        # 3.返回创建好的对象
        return obj


class Student(metaclass=MyMetaClass):
    def __init__(self, name):
        self.name = name

obj = Student('jason')
print(obj.name)
"""
__new__可以产生空对象
"""

标签:__,Python,self,元类,面向对象,init,print,type,之元类
From: https://www.cnblogs.com/kangssssh/p/16870484.html

相关文章

  • python import
    fromtest2import*import导入和fromimport导入,在内存上没有差别,都需要从头到尾全部编译一遍,并加载到内存中。这里如果在test2中定义__all__=['func1',....],这里限制了......
  • IOU计算-纯python
    iou计算代码,纯pythonfrom:https://blog.csdn.net/leviopku/article/details/81629492#!/usr/bin/envpython#encoding:utf-8defcompute_iou(rec1,rec2):......
  • Python学习笔记3
    Python学习笔记3       Python中的True和Falsepath=os.path.join('a','b')print(path)#a\bmessages=[]ifmessages==False:  print('[]就是False')m......
  • oop面向对象
    面向对象OOP面向过程&面向对象面向过程思想步骤清晰简单,第一步做什么,第二步做什么...面对过程适合处理一些较为简单的问题面向对象思想物以类聚,分类的思维模......
  • day30面向对象(4)
    目录面向对象的魔法对象魔法方法笔试题元类简介创建类的两种方式元类定制类的产生行为元类定制对象的产生行为魔法方法之双下new设计模式简介面向对象的魔法对象魔法方法......
  • 面向对象4魔法方法及元类
    目录面向对象的魔法方法魔法方法笔试题元类简介创建类的两种方式元类定制类的产生行为元类定制对象的产生行为魔法方法之双下new设计模式简介面向对象的魔法方法魔法方法......
  • esp32 micropython引脚电容值实现模拟按键
    frommachineimportTouchPad,Pin#引入touchpad模块fromtimeimportsleepimportutimetouch_up=TouchPad(Pin(12))#12是上touch_down=TouchPad(Pin(13)......
  • Python基础30
    今日内容概要面向对象之魔法方法基于魔法方法的笔试题元类简介创建类的两种方式元类定制类的产生行为元类定制对象的产生行为魔法方法之双下new方法设计模式简介......
  • python 入门 2 数字类型
    在编程时,经常会使用到数字来记录的情况,比如游戏分数、可视化。存储web等。python会根据数字的用法,以不同的方式来处理。1.整数python中的整数  加(+)减(-)乘(*)除(/)运算: ......
  • 14.面向对象编程
    1.初识面向对象想要通过面向对象去实现某个或某些功能时需要2步:定义类,在类中定义方法,在方法中去实现具体的功能。实例化类一个对象,通过对象去调用并执行方法。c......