文章目录
Python Meta Class
一、 万物皆对象
1、 简介
Python从设计之初就是一门面向对象的语言,它有一个重要的概念,即一切皆对象。
Python与java的区别:
Java虽然也是面向对象编程的语言,但是血统没有Python纯正。比如Java的八种基本数据类型之一int,在持久化的时候,就需要包装成Integer类对象。但是在python中,一切皆对象。数字、字符串、元组、列表、字典、函数、方法、类、模块等等都是对象,包括你的代码。
2、 Python对象
究竟何谓对象?不同的编程语言以不同的方式定义“对象”。某些语言中,它意味着所有对象必须有属性和方法;另一些语言中,它意味着所有的对象都可以子类化。
在Python中,定义是松散的,某些对象既没有属性也没有方法,而且不是所有的对象都可以子类化。但是Python的万物皆对象从感性上可以解释为:Python 中的一切都可以赋值给变量或者作为参数传递给函数。
符合Python对象的条件是:
- 能够直接赋值给一个变量
- 可以添加到集合对象中
- 能作为函数参数进行传递
- 可以作为函数返回值
从这里,大家就可以看出,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类和父类objectclass
:继承自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这个类
"""
返回一个类对象,将其属性置为大写
"""