python当中的metaclass

简单介绍

  • python中对象也是类,类作为一种特别的对象存在,特别之处就在于可以作为一个模板来生成对象(所有的类都是),暂且把python中的类称为类对象,类对象使用class定义。
  • 除了class定义, 我们也可以用type来创建一个类。
type(class_name, base_class, attrs)
# example
NewClass = type("NewCls", (), {"name":"bob"})
a = NewClass()
a.name
我们用type成功生成了一个类,他的意义在于,我可以在程序运行的过程中,使用代码动态的去定义一个类(*区别于那种传统的先用class定义完你用的类,然后实例化使用的方式*)

既然使用type可以动态创建类,代码种可能就会存在这样一种情况
cls = {"Ncls":{"bases":(), "attrs":{}}} (格式举例) cls_list = [] for k, v in cls_dict: new_cls = type(k, v["bases"], v["attrs"]) cls_list.append(new_lcs)
这里使用type,将一个字典或者列表,动态的转化生成一个类数组

  • metaclasss有什么用?type可以创建类,如果存在一个方法,返回一个type动态创建的类,在使用class定义类的时候,把这个方法赋值给metaclass,就可以实现动态的改变class的定义。代码说明一切,这里用py3语法。
def upper_attr(class_name, class_parents, class_attr):attrs = ((name, value)for name, value in class_attr.items() if not name.startswith('__'))uppercase_attrs = dict((name.upper(), value) for name, value in attrs)return type(class_name, class_parents, uppercase_attrs)class NewCls(metaclass=upper_attr):name = "lanix"sex = "male"
NewCls.NAME # lanix
NewCls.name    # AttributeError: type object 'NewCls' has no attribute 'name'

很明显,类定义时通过一个metaclass可以把定义的attrs中的属性key,全部变为大写, metaclass除了可以接受一个函数,也可以介绍一个type作为基类的类。类如

class UpperAttrMetaClass(type):def __new__(mcs, class_name, class_parents, class_attr):attrs = ((name, value) for name, value in class_attr.items() if not name.startswith('__'))uppercase_attrs = dict((name.upper(), value) for name, value in attrs)return super(UpperAttrMetaClass, mcs).__new__(mcs, class_name, class_parents, uppercase_attrs)class NewCls(metaclass=UpperAttrMetaClass):name = "lanix"sex = "male"

两者可以实现同样的效果

py2/3版本中的差别。网上搜索到的很多文章都是错的,这真让我崩溃

在py2中, 使用元类(metaclass)可以这么写, 很多介绍metaclass的文章都是这样介绍的,而且当__metaclass__ = MyMetaClass 跟类定义同级别时,会成为所有同级别的类的元类。

class NewClass:__metaclass__ = MyMetaClass

但是在py3版本中, 并不支持__metaclass__的写法,应该

class NewClass(metaclass=MyMetaClass):pass

一个简单的使用案例

比如在游戏开发中,要定义一个角色,它大概有几种动作(状态

最简单的方式可以

class BadMan:def __init__(self, name):self.name = nameself.state = ''def run(self):print(f'{self.name} is runing!')self.state = "run"def fight(self):print(f'{self.name} is fighting')self.state = "fight"b = BadMan("bob")
b.run()

定义都是固定不变的,不够灵活 ,也不够优雅。这里有一个使用metaclass的例子, 可以使用metaclass写一个fsm。

class Action(object):def __init__(self, act_desc):self.desc = act_descclass ManMeta(type):def __new__(cls, name, bases, attrs):actives = {}for k, v in attrs.items():if isinstance(v, Action):cls.add_action(actives, k, v)attrs.update(actives)return type.__new__(cls, name, bases, attrs)@classmethoddef add_action(cls, action_dict, active_name, action_obj):def active(self):self.state = active_nameprint(action_obj.desc)action_dict[active_name] = activeclass Hero(object, metaclass=ManMeta):walk = Action("from on place to another")fight = Action("use weapon to fight")die = Action("your hero is dying now")sleep = Action("fall asleep")def __init__(self):self.state = ""

这里首先定义了一个Active动作类,用来描述各种动作,
随后定义了一个metaclass,并使用这个metaclass 改变了Hero的创建过程,Hero.walk 定义中是一个 Action 实例,在ManMeta中,对这个walk这个属性进行了修改,变为一个类方法的定义函数,经过这一步神奇的转换之后。

z = Hero()
z.fight()      # use weapon to fight
z.state       # 'fight'

(给Action对象添加一个__call__(self) 也可以实现fight()调用,这里为了解释metaclass, 我们并不关心这些)

metaclass最成功的案例可以百度python orm 实现,metaclass最重要的是提供了一种灵活的类定义的方式。

python当中的metaclass使用相关推荐

  1. python编译器怎么运行不在路径中的py文件_对python当中不在本路径的py文件的引用详解...

    众所周知,如果py文件不在当前路径,那么就不能import,因此,本文介绍如下两种有效的方法: 方法1: 修改环境变量,在~/.bashrc里面进行修改,然后source ~/.bashrc 方法2: ...

  2. python提供了两种基本的数值类型_python数据分析(一) python当中的数据类型--数字和常用函数...

    python当中内置了多种数据类型,了解python内置的基本数据类型,有助于进行进行数据处理.第一篇我们将介绍python当中的数字. 我们将介绍每一种数字类型,他们适用的操作符,以及用于处理的内建 ...

  3. 超详细,Python当中的pip常用命令大全

    相信对于大多数熟悉Python的人来说,一定都听说并且使用过pip这个工具,但是对它的了解可能还不一定是非常的透彻,今天小编就来为大家介绍10个使用pip的小技巧,相信对大家以后管理和使用Python ...

  4. Python当中reverse()函数

    Hello大家好,今天我想和大家分享一下Python当中的reverse()函数 reverse()函数顾名思义就是反转的意思,但是我们要注意反转的内容只能是python当中的列表!千万不要忘记了.例 ...

  5. 关于在Python当中汉字日期的转换

    前几天在做项目的时候遇到了一个关于日期当中汉字转换的问题.平时系统获取的时间都是阿拉伯数字,比如在代码中输入下面的语句: print (datetime.datetime.now().year) 得到 ...

  6. 超详细!Python当中的pip常用命令大全!

    点击上方"菜鸟学Python",选择"星标"公众号 超级无敌干货,第一时间送达!!! 大家好,我是菜鸟哥. 相信对于大多数熟悉Python的人来说,一定都听说并 ...

  7. Python当中大小写字母与数字的转换 chr()函数,ord()函数,以及ascii_lowercase和ascii_uppercase

    Hello大家好,今天我想和大家分享一下在Python当中进行大小写字母与数字的转换: 如果大家想将数字转换成ascii码的话,就使用chr()函数就行,反之的话可以使用ord函数,例如: a = 9 ...

  8. 如果你是第一次接触Python当中的面向对象,请点击进来。

    2018年7月29日15:49:49 今天有时间写一篇关于Python面向对象入门的文章,其实面向对象是不属于某一门编程语言的,而是一种编程思想,如果你是第一次接触面向对象,你需要弄懂下面几个问题: ...

  9. python——type()、metaclass元类和精简ORM框架

    1.type()函数 #type()函数既可以返回一个对象的类型,又可以创建出新的类型, # 比如,我们可以通过type()函数创建出Hello类,而无需通过class Hello(object).. ...

最新文章

  1. java rabbitmq 绑定_RabbitMQ:交换,队列和绑定 - 谁设置了什么?
  2. PHP框架 one 1.6.0 发布
  3. data transformation python_Python数据分析(方睿)
  4. python 写linux mysql_(linux)python之mysql数据库操作环境搭建
  5. 初谈Git(本机克隆项目远程仓库)
  6. Windows Azure 真实案例:CCH 财政服务独立软件开发商(ISV)通过托管服务获得了灵活性并节省成本...
  7. 前端学习(2655):vue2中用ref实现计算器
  8. java swing进度条_Java Swing创建自定义闪屏:在闪屏上添加Swing进度条控件(转)
  9. 金融行业 | 电子银行系统性能优化解决方案
  10. 机器学习之保存与加载.pickle模型文件
  11. 听说大家想补补算法和数据结构,给大家推荐一个GitHub 15k星的图文版开源项目...
  12. 磁盘不见了只剩一个c盘_教你如何处理只剩一个C盘
  13. 局域网ip扫描工具_中科院网络工程师网络安全视频教程10端口扫描
  14. spring基础知识(IOC、DI、AOP)
  15. 化妆品护肤DiY的广告界面 简单的jquery 图片无缝滚动
  16. 报错笔记-[error] 1615#0: *14 open() “/usr/local/nginx/html/course/zk.jpg“ failed (2: No such file or dir
  17. POJ 2395 Out of Hay 最小生成树 Kruskal
  18. 基于vs实现的socket—udp图片传送实例详解
  19. 论从容自信---张含韵和涛声依旧有感
  20. 计算机专业面向的职业,职业面向及职业能力要求

热门文章

  1. Java实现虾米音乐免虾币下载
  2. 不用摄像头和激光雷达,四足机器人「凭感觉」越野:ANYmal登上Science子刊封面...
  3. python实战-JSON形式爬虫-批量爬取图片并下载
  4. 个人目标日历定制制作小工具微信小程序(含源码)
  5. 实训程序:用户登陆注册,实现宠物的领养
  6. “i卫星”——行星中的数字编码
  7. 求解一个数的立方根(想不懂都难)
  8. Word或Excel 转Pdf 工具类(License 去水印)
  9. 用lm_sensor来看你的主板和CPU的温度
  10. Inferring temporal motifs for travel pattern analysis using large scale smart card data