首页 > 其他分享 >面向对象之元类

面向对象之元类

时间:2024-01-13 23:34:44浏览次数:28  
标签:__ name print 面向对象 init MyType class 之元类

【一】常用的魔法方法

【1】初始化对象的属性__init__

【二】元类

【1】什么是元类

  • 一切源于一句话:Python中一切皆对象
  • 八大基本数据类型是对象
  • 类实例化得到的对象也是对象
  • 其实类本身也是一种对象
class Human:
    def __init__(self, name, age):
        self.name = name
        self.age = age


obj = Human('hqq', 21)

print(type(obj))  # <class '__main__.Human'>

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

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

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

  • 通过查看每一种数据的数据类型,我们会发现都共同拥有一个类
  • 这个类就是 type 我们也称之为元类

【2】产生类的两种方式

(1)直接关键字创建

  • 语法
关键字(class) 类名(Student)继承的父类(默认是object):
    # 类体代码
  • 示例
class Human:
    def __init__(self, name, age):
        self.name = name
        self.age = age

(2)通过 type 创建

def read():
    ...


Human = type('Human', (object,), {'name': 'hqq', 'age': 21, 'read': read})
print(type(Human)) # <class 'type'>
print(Human.__dict__)

【3】为什么要使用元类

  • 元类可以控制类的创建,也就意味着我们可以高度定制类的具体行为
    • 比如,当我们掌控了食品的生产过程,我们就可以在里面随便动手脚

【4】元类的基本使用

(1)需求

  • 要求所有类的名字不能有下划线_

(2)思考

  • 我们应该在哪里定制这些代码
    • 类的产生过程也许我们还不熟悉
    • 但是对象的产生过程,是通过类内的 __init__ 方法实现的
    • 那我们猜,在元类里面也有一个 __init__方法

(3)基本使用

class MyType(type):
    def __init__(cls, class_name, class_bases, class_dict):
        print("MyType的__init__被调用,class_name是:", class_name)
        print("MyType的__init__被调用,class_bases是:", class_bases)
        print("MyType的__init__被调用,class_dict是:", class_dict)
        super().__init__(class_name, class_bases, class_dict)


# 元类的使用区别于我们继承中使用父类的那种形式
# 元类的使用采用  metaclass 关键字声明
# 在前面学习 abc 模块的时候,我们也使用过类似的语法

# 【1】创建一个类
class MyClass(object, metaclass=MyType):
    ...


# 【2】初始化类
MyClass()

# MyType的__init__被调用,class_name是: MyClass
# MyType的__init__被调用,class_bases是: (<class 'object'>,)
# MyType的__init__被调用,class_dict是: {'__module__': '__main__', '__qualname__': 'MyClass'}

(4)进阶使用

  • 限制类名不能有下划线
class MyType(type):
    def __init__(cls, class_name, class_bases, class_dict):
        print("MyType的__init__被调用,class_name是:", class_name)
        print("MyType的__init__被调用,class_bases是:", class_bases)
        print("MyType的__init__被调用,class_dict是:", class_dict)
        # super().__init__(class_name, class_bases, class_dict)
        if '_' in class_name:
            raise NameError('类名不能有下划线')


class H_uman(metaclass=MyType):
    def __init__(self, name, age):
        self.name = name
        self.age = age


obj = H_uman('hqq', 21)

'''
Traceback (most recent call last):
  File "D:\python28\面向对象\导读.py", line 899, in <module>
    class H_uman(metaclass=MyType):
  File "D:\python28\面向对象\导读.py", line 896, in __init__
    raise NameError('类名不能有下划线')
NameError: 类名不能有下划线
'''
  • 类名有下划线有会抛出错误

【5】元类的进阶使用

(1)引入

  • 当对象用括号调用时,必定会调用对象所属类的里面的__call__方法,并且得到对应的返回值
  • 对象() ---->类里面的__call__方法
  • 类()---->自定元类里面的__call__方法
  • 自定元类()---->内置元类里面的__call__方法
class MyType(type):
    def __init__(cls, class_name, class_bases, class_dict):
        print("MyType的__init__被调用,class_name是:", class_name)
        print("MyType的__init__被调用,class_bases是:", class_bases)
        print("MyType的__init__被调用,class_dict是:", class_dict)
        if '_' in class_name:
            raise NameError('类名不能有下划线')
        super().__init__(class_name, class_bases, class_dict)

    def __call__(self, *args, **kwargs):
        print('我被MyType里面的call方法触发了')
        print(args, kwargs)
        obj = super().__call__(*args, **kwargs)
        return obj


class Human(metaclass=MyType):
    def __init__(self, name):
        self.name = name



obj = Human('hqq')
'''
MyType的__init__被调用,class_name是: Human
MyType的__init__被调用,class_bases是: ()
MyType的__init__被调用,class_dict是: {'__module__': '__main__', '__qualname__': 'Human', '__init__': <function Human.__init__ at 0x0000028A154340E0>}
我被MyType里面的call方法触发了
('hqq',) {}

'''

(2)定制对象产生过程

class MyType(type):
    def __init__(cls, class_name, class_bases, class_dict):
        print("MyType的__init__被调用,class_name是:", class_name)
        if '_' in class_name:
            raise NameError('类名不能有下划线')
        super().__init__(class_name, class_bases, class_dict)

    def __call__(self, *args, **kwargs):
        print('我被MyType里面的call方法触发了')
        print(args, kwargs)
        if kwargs:
            raise TypeError('必须用位置传参')
        obj = super().__call__(*args, **kwargs)
        return obj


class Human(metaclass=MyType):
    def __init__(self, name):
        self.name = name



obj = Human(name='hqq')

'''
Traceback (most recent call last):
  File "D:\python28\面向对象\导读.py", line 912, in <module>
    obj = Human(name='hqq')
          ^^^^^^^^^^^^^^^^^
  File "D:\python28\面向对象\导读.py", line 901, in __call__
    raise TypeError('必须用位置传参')
TypeError: 必须用位置传参

'''

【6】__new__方法

  • __new__用于产生空对象(类),相当于人的骨架
  • __init__用于实例化对象(类),相当于人的血肉
class MyType(type):
    def __init__(cls, class_name, class_bases, class_dict):
        print("MyType的__init__被调用,class_name是:", class_name)
        if '_' in class_name:
            raise NameError('类名不能有下划线')
        super().__init__(class_name, class_bases, class_dict)

    def __call__(self, *args, **kwargs):
        print('我被MyType里面的call方法触发了')
        print(args, kwargs)
        if kwargs:
            raise TypeError('必须用位置传参')
        obj = super().__call__(*args, **kwargs)
        return obj

    def __new__(cls, *args, **kwargs):
        print('我在MyType中被__new__执行了')
        return super().__new__(cls,*args, **kwargs)


class Human(metaclass=MyType):
    def __init__(self, name):
        self.name = name

标签:__,name,print,面向对象,init,MyType,class,之元类
From: https://www.cnblogs.com/Hqqqq/p/17963205

相关文章

  • 面向对象之封装
    【一】面向对象三大特性面向对象编程有三大特性:封装、继承、多态其中最重要的一个特性就是封装。封装指的就是把数据与功能都整合到一起【1】什么是封装就是对具体对象的一种抽象简单理解就是把不想让别人看到的对象藏起来【2】为什么要封装有些敏感数据不想......
  • 什么是面向对象
    面向过程&面向对象面向过程思想按顺序进行,线性思维步骤清晰简单,第一步做什么,第二步做什么……面对过程适合处理一些较为简单的问题面向对象思想属性加方法变成一个类物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最......
  • Python面向对象之反射
    【一】反射【1】什么是反射反射是一种程序可以访问、检测和修改其本身状态或行为的能力。在Python中,反射主要指通过字符串的形式操作对象的属性。【2】Python中的反射通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)【二】反射方法......
  • Python面向对象之派生
    派生【一】概要"派生"(Derivation)是指在面向对象编程中,通过创建新的类,基于已有的类(通常称为父类或基类)来构建新的类,以获取和扩展父类的属性和方法。在这个过程中,新创建的类称为子类或派生类。通俗来讲,派生是指,子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法【......
  • 面向对象的三大特性及派生和组合
    面向对象的三大特性面向对象编程有三大特性:封装、继承、多态-->派生和组合【一】封装【1】什么是封装在程序设计中,封装(Encapsulation)是对具体对象的一种抽象封装就是对具体对象的一种抽象简单理解就是将不想让别人看到的东西全部藏起来【2】为什么要封装封装数......
  • java基础语法面向对象之单个对象内存图
    一:概述在面向对象的学习中,需要去了解对象的内存图,在这里以单个对象的内存图为例进行讲解。二:具体说明<1>代码publicclassStudent{Stringname;intage;publicvoidstudy(){System.out.println(name+"好好学习");......
  • python之元类
    【什么是元类】元类:就是用来实例化产生类的类关系:元类-----实例化-----》类(People)-----实例化-----》对象(obj)一切都来源于一句话:一切皆为对象【演示】   【如何自定义元类来控制类的产生】   【__call__方法】  【自定义元类控制类的调用=====》......
  • Python面向对象之绑定方法和非绑定方法
    绑定方法与非绑定方法【一】概要在Python中,绑定方法是指将类的实例与类的方法关联起来的过程。绑定方法包含类实例作为第一个参数,通常被称为self。当通过实例调用类的方法时,Python会自动传递实例作为第一个参数,这个过程就是方法绑定。【二】常用方法【1】绑定方法(动态方......
  • 29-Scala-面向对象
    1.面向对象编程基础1.1定义类基本语法:[修饰符]class类名{//code}Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)一个Scala源文件可以包含多个类1.2成员变量属性的定义语法同变量:[访问修饰符]var属性名称[:类型]=属性值......
  • Python教程(22)——Python面向对象的属性和方法
    在Python面向对象编程中,属性和方法是类及其对象的重要组成部分。如果说封装、继承和多态是面向对象编程中的思想,那么类的属性和方法就是骨架,因为有属性和方法,面向对象编程才变的有血有肉。属性属性是类或对象所拥有的数据,它用于描述对象的特征和状态。属性可以是实例属性(对象特......