Python如何定义有可选参数的元类


Posted in Python onJuly 31, 2020

问题

你想定义一个元类,允许类定义时提供可选参数,这样可以控制或配置类型的创建过程。

解决方案

在定义类的时候,Python允许我们使用 ``metaclass``关键字参数来指定特定的元类。 例如使用抽象基类:

from abc import ABCMeta, abstractmethod
class IStream(metaclass=ABCMeta):
  @abstractmethod
  def read(self, maxsize=None):
    pass

  @abstractmethod
  def write(self, data):
    pass

然而,在自定义元类中我们还可以提供其他的关键字参数,如下所示:

class Spam(metaclass=MyMeta, debug=True, synchronize=True):
  pass

为了使元类支持这些关键字参数,你必须确保在 __prepare__() , __new__() __init__() 方法中 都使用强制关键字参数。就像下面这样:

class MyMeta(type):
  # Optional
  @classmethod
  def __prepare__(cls, name, bases, *, debug=False, synchronize=False):
    # Custom processing
    pass
    return super().__prepare__(name, bases)

  # Required
  def __new__(cls, name, bases, ns, *, debug=False, synchronize=False):
    # Custom processing
    pass
    return super().__new__(cls, name, bases, ns)

  # Required
  def __init__(self, name, bases, ns, *, debug=False, synchronize=False):
    # Custom processing
    pass
    super().__init__(name, bases, ns)

讨论

给一个元类添加可选关键字参数需要你完全弄懂类创建的所有步骤, 因为这些参数会被传递给每一个相关的方法。 __prepare__() 方法在所有类定义开始执行前首先被调用,用来创建类命名空间。 通常来讲,这个方法只是简单的返回一个字典或其他映射对象。 __new__() 方法被用来实例化最终的类对象。它在类的主体被执行完后开始执行。 __init__() 方法最后被调用,用来执行其他的一些初始化工作。

当我们构造元类的时候,通常只需要定义一个 __new__() __init__() 方法,但不是两个都定义。 但是,如果需要接受其他的关键字参数的话,这两个方法就要同时提供,并且都要提供对应的参数签名。 默认的 __prepare__() 方法接受任意的关键字参数,但是会忽略它们, 所以只有当这些额外的参数可能会影响到类命名空间的创建时你才需要去定义 __prepare__() 方法。

通过使用强制关键字参数,在类的创建过程中我们必须通过关键字来指定这些参数。

使用关键字参数配置一个元类还可以视作对类变量的一种替代方式。例如:

class Spam(metaclass=MyMeta):
  debug = True
  synchronize = True
  pass

将这些属性定义为参数的好处在于它们不会污染类的名称空间, 这些属性仅仅只从属于类的创建阶段,而不是类中的语句执行阶段。 另外,它们在 __prepare__() 方法中是可以被访问的,因为这个方法会在所有类主体执行前被执行。 但是类变量只能在元类的 __new__()__init__() 方法中可见。

以上就是Python如何定义有可选参数的元类的详细内容,更多关于Python定义元类的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python将文本转换成图片输出的方法
Apr 28 Python
python更新列表的方法
Jul 28 Python
Django 添加静态文件的两种实现方法(必看篇)
Jul 14 Python
详解K-means算法在Python中的实现
Dec 05 Python
使用python编写简单的小程序编译成exe跑在win10上
Jan 15 Python
浅谈Python traceback的优雅处理
Aug 31 Python
windows下cx_Freeze生成Python可执行程序的详细步骤
Oct 09 Python
python 运用Django 开发后台接口的实例
Dec 11 Python
python遍历文件目录、批量处理同类文件
Aug 31 Python
Python logging日志模块 配置文件方式
Jul 12 Python
python中@contextmanager实例用法
Feb 07 Python
python FTP编程基础入门
Feb 27 Python
Python爬虫爬取糗事百科段子实例分享
Jul 31 #Python
Python如何对齐字符串
Jul 30 #Python
Python3爬虫关于代理池的维护详解
Jul 30 #Python
Python读写压缩文件的方法
Jul 30 #Python
Python3爬虫里关于代理的设置总结
Jul 30 #Python
Python 如何创建一个简单的REST接口
Jul 30 #Python
Python3爬虫里关于识别微博宫格验证码的知识点详解
Jul 30 #Python
You might like
PHP输出控制功能在简繁体转换中的应用
2006/10/09 PHP
php cache类代码(php数据缓存类)
2010/04/15 PHP
PHP的简易冒泡法代码分享
2012/08/28 PHP
CentOS 6.2使用yum安装LAMP以及phpMyadmin详解
2013/06/17 PHP
解决ThinkPHP关闭调试模式时报错的问题汇总
2015/04/22 PHP
大家在抢红包,程序员在研究红包算法
2015/08/31 PHP
laravel 5.1下php artisan migrate的使用注意事项总结
2017/06/07 PHP
PHP基于双向链表与排序操作实现的会员排名功能示例
2017/12/26 PHP
零基础php编程好学吗
2019/10/11 PHP
javascript ajax 仿百度分页函数
2013/10/29 Javascript
new Date()问题在ie8下面的处理方法
2014/07/31 Javascript
JQuery使用index方法获取Jquery对象数组下标的方法
2015/05/18 Javascript
jQuery实现判断滚动条到底部
2015/06/23 Javascript
微信小程序 框架详解及实例应用
2016/09/26 Javascript
详解jQuery中基本的动画方法
2016/12/14 Javascript
原生js和css实现图片轮播效果
2017/02/07 Javascript
Ajax实现不刷新取最新商品
2017/03/01 Javascript
完美解决vue 中多个echarts图表自适应的问题
2020/07/19 Javascript
[01:56]2014DOTA2西雅图邀请赛 MVP外卡赛老队长精辟点评
2014/07/09 DOTA
一篇不错的Python入门教程
2007/02/08 Python
Python反射用法实例简析
2017/12/22 Python
Python使用matplotlib绘制正弦和余弦曲线的方法示例
2018/01/06 Python
用Python进行简单图像识别(验证码)
2018/01/19 Python
python3中获取文件当前绝对路径的两种方法
2018/04/26 Python
Tensorflow中的placeholder和feed_dict的使用
2018/07/09 Python
python无限生成不重复(字母,数字,字符)组合的方法
2018/12/04 Python
Python3.5基础之NumPy模块的使用图文与实例详解
2019/04/24 Python
numpy中生成随机数的几种常用函数(小结)
2020/08/18 Python
安装不同版本的tensorflow与models方法实现
2021/02/20 Python
金牌葡萄酒俱乐部:Gold Medal Wine Club
2017/11/02 全球购物
菲律宾购物网站:Lazada菲律宾
2018/04/05 全球购物
商场开业庆典策划方案
2014/06/02 职场文书
公司保洁员管理制度
2015/08/04 职场文书
vue使用refs获取嵌套组件中的值过程
2022/03/31 Vue.js
Python中第三方库Faker的使用详解
2022/04/02 Python
MySQL数据库Innodb 引擎实现mvcc锁
2022/05/06 MySQL