Python 使用元类type创建类对象常见应用详解


Posted in Python onOctober 17, 2019

本文实例讲述了Python 使用元类type创建类对象。分享给大家供大家参考,具体如下:

type("123") 可以查看变量的类型;同时 type("类名",(父类),{类属性:值,类属性2:值}) 可以创建一个类。

在Python中不建议一个函数具有不同的功能(重载);type()具有不同的功能是为了兼容之前的版本。

类可以创建实例对象,类对象是由元类创建的。 (元类创建类,类创建实例对象)

type就是元类(type本质上就是一个类)

demo.py(用元类type创建类):

# 通过class关键字创建类
class MyClass1(object):
  name = "张三" # 类属性 (所有实例对象共用)
  age = 23
# 通过type创建类。 type()返回的是创建的类对象的引用。
Test2 = type("MyClass2",(object,),{"name":"张三","age":23}) # Test2是MyClass2类的引用,一般变量名和类名保持一致。
print(Test2()) # <__main__.MyClass2 object at 0x7fa05a4ca9e8>

demo.py(用type创建带有方法的类):

# 实例方法
def print_b(self):
  print(self.num)
# 静态方法
@staticmethod
def print_static():
  print("----haha-----")
# 类方法
@classmethod
def print_class(cls):
  print(cls.num)
# 用type创建类
B = type("B", (object,), {"num":100, "print_b": print_b, "print_static": print_static, "print_class": print_class})
b = B()
b.print_b()   # 100
b.print_static() # ----haha-----
b.print_class()  # 100

元类的应用

在定义一个类的时候可以为其指定__metaclass__属性(指定创建该类的元类),默认使用type元类创建类对象。

通过指定自定义的元类,可以对类的创建进行拦截。可以对类名、继承的父类、属性(方法)做一些预处理。

例如:将类名大写,默认继承object类,添加、修改属性(方法)名(私有属性的伪私有化就是通过修改属性名实现的)。

装饰器是对函数进行功能扩展(不用修改原代码),而元类可以对类进行功能扩展(添加额外的属性/方法)。

demo.py(用函数指定__metaclass__属性):

#-*- coding:utf-8 -*-
def upper_attr(class_name, class_parents, class_attr):
  # class_name 会保存类的名字 Foo
  # class_parents 会保存类的父类 object
  # class_attr 会以字典的方式保存所有的类属性/方法
  # 遍历属性字典,把不是__开头的属性名字变为大写
  new_attr = {}
  for name, value in class_attr.items():
    if not name.startswith("__"):
      new_attr[name.upper()] = value
  # 调用type来创建一个类
  return type(class_name, class_parents, new_attr)
class Foo(object, metaclass=upper_attr): # python3的方式
  # python2.x的方式。
  # __metaclass__ = upper_attr # 设置Foo类的元类为upper_attr
  bar = 'bip'
print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))
f = Foo()
print(f.BAR)

demo.py(用类指定__metaclass__属性):

class UpperAttrMetaClass(type):
  # __new__ 是在__init__之前被调用的特殊方法
  # __new__是用来创建对象并返回之的方法
  # 而__init__只是用来将传入的参数初始化给对象
  # 你很少用到__new__,除非你希望能够控制对象的创建
  # 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
  # 如果你希望的话,你也可以在__init__中做些事情
  # 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
  def __new__(cls, class_name, class_parents, class_attr):
    # 遍历属性字典,把不是__开头的属性名字变为大写
    new_attr = {}
    for name, value in class_attr.items():
      if not name.startswith("__"):
        new_attr[name.upper()] = value
    # 方法1:通过'type'来做类对象的创建
    return type(class_name, class_parents, new_attr)
    # 方法2:复用type.__new__方法
    # 这就是基本的OOP编程,没什么魔法
    # return type.__new__(cls, class_name, class_parents, new_attr)
# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
  bar = 'bip'
# python2的用法
# class Foo(object):
#   __metaclass__ = UpperAttrMetaClass
#   bar = 'bip'
print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True
f = Foo()
print(f.BAR)
# 输出:'bip'

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
深入讲解Python中的迭代器和生成器
Oct 26 Python
Python基于回溯法子集树模板解决数字组合问题实例
Sep 02 Python
python中利用队列asyncio.Queue进行通讯详解
Sep 10 Python
谈一谈基于python的面向对象编程基础
May 21 Python
pygame实现非图片按钮效果
Oct 29 Python
python如果快速判断数字奇数偶数
Nov 13 Python
基于Python批量生成指定尺寸缩略图代码实例
Nov 20 Python
使用Python的Turtle库绘制森林的实例
Dec 18 Python
Python使用enumerate获取迭代元素下标
Feb 03 Python
Keras: model实现固定部分layer,训练部分layer操作
Jun 28 Python
如何用Python进行时间序列分解和预测
Mar 01 Python
Python趣味挑战之实现简易版音乐播放器
May 28 Python
Python with关键字,上下文管理器,@contextmanager文件操作示例
Oct 17 #Python
浅析Python+OpenCV使用摄像头追踪人脸面部血液变化实现脉搏评估
Oct 17 #Python
Python 3.8正式发布重要新功能一览
Oct 17 #Python
Python 装饰器@,对函数进行功能扩展操作示例【开闭原则】
Oct 17 #Python
python实现复制文件到指定目录
Oct 16 #Python
如何解决django-celery启动后迅速关闭
Oct 16 #Python
Python发送邮件的实例代码讲解
Oct 16 #Python
You might like
德劲1103的维修打理经验
2021/03/02 无线电
PHP数据缓存技术
2007/02/14 PHP
PHP常用技术文之文件操作和目录操作总结
2014/09/27 PHP
php约瑟夫问题解决关于处死犯人的算法
2015/03/23 PHP
php简单计算页面加载时间的方法
2015/06/19 PHP
JavaScript获取onclick、onchange等事件值的代码
2013/07/22 Javascript
js确认删除对话框效果的示例代码
2014/02/20 Javascript
JavaScript开发人员的10个关键习惯小结
2014/12/05 Javascript
浅谈javascript的调试
2015/01/28 Javascript
Python脚本后台运行的几种方式
2015/03/09 Javascript
实例讲解jquery中mouseleave和mouseout的区别
2016/02/17 Javascript
JS中mouseover和mouseout多次触发问题如何解决
2016/06/06 Javascript
返回函数的JavaScript函数
2016/06/14 Javascript
Vue.js 表单校验插件
2016/08/14 Javascript
vue日历/日程提醒/html5本地缓存功能
2019/09/02 Javascript
解决windows下Sublime Text 2 运行 PyQt 不显示的方法分享
2014/06/18 Python
python技能之数据导出excel的实例代码
2017/08/11 Python
python smtplib模块自动收发邮件功能(二)
2018/05/22 Python
python检测IP地址变化并触发事件
2018/12/26 Python
TensorFlow Saver:保存和读取模型参数.ckpt实例
2020/02/10 Python
tensorflow指定CPU与GPU运算的方法实现
2020/04/21 Python
浅谈keras中的batch_dot,dot方法和TensorFlow的matmul
2020/06/18 Python
HTML5中div、article、section的区别及使用介绍
2013/08/14 HTML / CSS
Html5实现二维码扫描并解析
2016/01/20 HTML / CSS
HTML5拖拉上传文件的简单实例
2017/01/11 HTML / CSS
印尼旅游网站:via
2017/11/12 全球购物
马来西亚在线健康商店:Medipal Malaysia
2020/04/13 全球购物
高中的职业生涯规划书
2013/12/28 职场文书
六年级语文下册教学计划
2015/01/22 职场文书
工会经费申请报告
2015/05/15 职场文书
2015年小学财务工作总结
2015/07/20 职场文书
2016年学校综治宣传月活动总结
2016/03/16 职场文书
导游词之贵州百里杜鹃
2019/10/29 职场文书
详解python网络进程
2021/06/15 Python
MySQL连表查询分组去重的实现示例
2021/07/01 MySQL
日元符号 ¥
2022/02/17 杂记