Python元类详解

Python Meta Class

一、 万物皆对象

1、 简介

Python从设计之初就是一门面向对象的语言,它有一个重要的概念,即一切皆对象。

Python与java的区别:

Java虽然也是面向对象编程的语言,但是血统没有Python纯正。比如Java的八种基本数据类型之一int,在持久化的时候,就需要包装成Integer类对象。但是在python中,一切皆对象。数字、字符串、元组、列表、字典、函数、方法、类、模块等等都是对象,包括你的代码。

2、 Python对象

究竟何谓对象?不同的编程语言以不同的方式定义“对象”。某些语言中,它意味着所有对象必须有属性和方法;另一些语言中,它意味着所有的对象都可以子类化。

在Python中,定义是松散的,某些对象既没有属性也没有方法,而且不是所有的对象都可以子类化。但是Python的万物皆对象从感性上可以解释为:Python 中的一切都可以赋值给变量或者作为参数传递给函数。

符合Python对象的条件是:

  1. 能够直接赋值给一个变量
  2. 可以添加到集合对象中
  3. 能作为函数参数进行传递
  4. 可以作为函数返回值

从这里,大家就可以看出,Python中一切皆为对象,一切都符合这些条件

Python对象都会有三个特征

  • 身份,即是存储地址,可以通过**id()**这个方法来查询
  • 类型,即对象所属的类型,可以用**type()**方法来查询
  • 值,都会有各自的数据
i = 2
print(id(i))  # 查询i变量的内存地址,代码实例
print(type(i))  # 查询i变量的类型
print(i)  # 获取i变量所对应的值

对象的属性:大部分 Python 对象有属性、值或方法,使用句点(.)标记法来访问属性。最常见的属性是函数和方法,一些 Python 对象也有数据属性,如:类、模块、文件等。

3、 type|object|class

3.1 关系

首先,我们通过一段代码来理解:

class MyClass(object):
    pass

print(type(MyClass()))  # 类的实例对象属于 MyClass
print(type(MyClass))  # 发现类的对象属于 type
print(type(int))  # 发现int类也属于 type
print(type.__base__)  # 发现其父类是 object

三个之间的关系:

  • object:object类是所有类(class)的父类,包括type类,object类的父类为空
  • type:type类是所有类的类型,即为所有类(class)都可由type实例化而来,包括type类和父类object
  • class:继承自object,同时,由type进行实例化。其中,type就是我们所要讲的元类(metaclass)

3.2 创建类的第二中方式

传统创建类的方式:

# 我们传统的实现方式

class MyClass(object):
    def get(self) -> None:
        print("类获取了一个信息", self.info)
    info = "hello"

c = MyClass()
c.get() 

那我们知道了所有类都可以由type实例化来的,那么我们怎么实例化呢?我们如何将上面传统创建类转化为使用type创建类呢?:

def get(self) -> None:
    """定义类内部需要运行的函数"""
    print("类获取了一个信息", self.info)

MyClass = type("MyClass", (object, ), {
   "get": get, "info": "hello"})

c = MyClass()
if hasattr(c, "get"):  # 判断是否有get函数
    getattr(c, "get", None)()  # 获取get函数,并运行函数
else:
    print("该类内部没有get函数")

二、 元类

1、 什么是元类

MetaClass元类,本质也是一个类,但和普通类的用法不同,它可以对类内部的定义(包括类属性和类方法)进行动态的修改。可以这么说,使用元类的主要目的就是为了实现在创建类时,能够动态地改变类中定义的属性或者方法。

不要从字面上去理解元类的含义,事实上 MetaClass 中的 Meta 这个词根,起源于希腊语词汇 meta,包含“超越”和“改变”的意思。

  • 什么是类?可能谁都知道,类就是用来创建对象的「模板」。
  • 那什么是元类呢?一句话通俗来说,元类就是创建类的「模板」。
  • 为什么type能用来创建类?因为它本身是一个元类。使用元类创建类,那就合理了。

type是Python在背后用来创建所有类的元类,我们熟知的类的始祖 object 也是由type创建的。更有甚者,连type自己也是由type自己创建的,这就过份了。

2、 调用流程

python创建类的流程为:

通过创建流程,我们可以知道,元类接收的参数为(__name: str, **__bases: tuple[type, ...]**, __dict: dict[str, Any], **kwds: Any),这个参数即为type()函数需要传入的参数

同时,这个元类可以是函数或者类,但是必须要是一个可调用对象,同时,需要返回一个类

3、 函数做元类

我们首先来学习,使用函数作为元类,

我们来实现一个将类里面的所有属性名称转换为大写:

# 元类会自动获取通常传给`type`的参数
def upper_attr(_class, _object, _attr):
    """
      返回一个类对象,将其属性置为大写
    """

    # 过滤出所有开头不为'__'的属性,置为大写
    uppercase_attr = {
   }
    for name, val in _attr.items():
        if not name.startswith('__'):
            uppercase_attr[name.upper()] = val
        else:
            uppercase_attr[name] = val

    # 利用'type'创建类,同时将这个类进行返回
    return type(_class, _object, uppercase_attr)


class Foo(metaclass=upper_attr):  # 创建对象时,其会经过 metaclass 来创建,再使用自身的方法进行实例化
    bar = 'bip'

print(hasattr(Foo, 'bar'))  
print(hasattr(Foo, 'BAR'))

f = Foo()
print(f.BAR)

4、 类做元类

类做元类,有两种方式,一种是使用__new__方法实现元类,另一种是使用__call__来实现元类:

还是通过上面的实例:

使用__new__方法来实现元类:

class UpperAttrMetaClass(type):  # 注意,元类必须要继承type这个类
    """
      返回一个类对象,将其属性置为大写
    """
    
  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SteveKenny

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值