[TimLinux] Python 再谈元类 metaclass
本博文通过对以下链接进行理解后,编写。
https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python
1. 类
类也是对象,具有对象的特点:
- 你可以将它赋值给变量
- 你可以copy它
- 你可以给它添加属性
- 你可以把它作为函数参数进行传递
类定义语法:
class Foo(object): pass 说明:
1. 这是一种语法糖,一种对类对象的声明方式,与def func, a = 123, 本质上没有区别,都是为了创建一个对象。
2. 对象的创建都关联到一个类,比如 a = 123 关联的类是 'int', b = 'hello' 关联的类是 'str', def func(): pass 关联的类是 'function', 而 class Foo(object): pass 关联的类就是元类 'metaclass', 默认为 'type'
对象重要特性:动态创建,你可以随时随地在你需要的地方创建对象,类也可以动态创建。
2. 动态创建
根据函数参数来创建类,看起来像是类工厂,但是动态性不够。
def choose_class(name):
if name == 'foo':
class Foo(object): pass
return Foo # return the class, not an instance
else:
class Bar(object): pass
return Bar >>> MyClass = choose_class('foo')
>>> print(MyClass) # the function returns a class, not an instance
<class '__main__.Foo'>
>>> print(MyClass()) # you can create an object from this class
<__main__.Foo object at 0x89c6d4c>
真正的动态创建,是通过元类(默认type类构造函数)来创建:
# 创建类
>>> Foo = type('Foo', (), {'bar':True})
>>> print(Foo)
<class '__main__.Foo'>
>>> print(Foo.bar)
True
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x8a9b84c>
>>> print(f.bar)
True # 创建子类
>>> FooChild = type('FooChild', (Foo,), {})
>>> print(FooChild)
<class '__main__.FooChild'>
>>> print(FooChild.bar) # bar is inherited from Foo
True # 给子类分配实例方法
>>> def echo_bar(self):
... print(self.bar)
...
>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
>>> hasattr(Foo, 'echo_bar')
False
>>> hasattr(FooChild, 'echo_bar')
True
>>> my_foo = FooChild()
>>> my_foo.echo_bar()
True # 再分配一个实例方法
>>> def echo_bar_more(self):
... print('yet another method')
...
>>> FooChild.echo_bar_more = echo_bar_more
>>> hasattr(FooChild, 'echo_bar_more')
True
3. 动态创建语法糖
为此 python 语言本身又提供了一个语法糖,在声明类的时候,就指定后台自动创建这个类的方法,方法就是 __metaclass__ 变量(python2.7), metaclass=xxx(python3.x)。示例:
# 文件保存为:mymetaclass.py
# 执行 python2 metaclass.py def upper_attr(name, parents, attributes):
new_attributes = {}
for n, v in attributes.items():
if not n.startswith('__'):
uppercase_attr[n.upper()] = v
else:
uppercase_attr[n] = v
return type(name, parents, new_attributes) __metaclass__ = upper_attr # py3这个无法工作 class Foo(): # py3,需要使用这个语法:class Foo(metaclass=upper_attr):
bar = 'bip' def __init__(self):
self.link = "link"
def func(self):
print("Enter func") # 类属性,函数都被转换为大写了
print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # True print(hasattr(Foo, 'func')) # False
print(hasattr(Foo, 'FUNC')) # True # 元类转换了类属性,但是没有转换实例属性, __init__ 内的变量没有被转换
print(hasattr(Foo, 'link')) # False
print(hasattr(Foo, 'LINK')) # False print(hasattr(Foo(), 'link')) # True
print(hasattr(Foo(), 'LINK')) # False
以上使用的是函数作为元类实现方式,也可以直接使用类作为元类,元类中实现的是 __new__ 方法,在生成类对象之前会被调用的方法即为 __new__ 方法。而不是 __init__ 方法, __init__ 方法是操作的类对象返回之后,创建的实例对象的初始化行为。
# metaclass 控制的是 __new__ 方法,而不是 __init__ 方法
class UpperAttrMetaclass(type):
def __new__(cls, name, parents, attributes):
new_attributes = {}
for n, v in attributes.items():
if not n.startswith('__'):
new_attributes[n.upper()] = v
else:
new_attributes[n] = v
#以下返回值推荐使用super方法,对当前示例两者效果相同,使用super可以使
#当前元类能够继承其他元类
#return type.__new__(cls, name, parents, new_attributes)
#return super(UpperAttrMetaclass, cls).__new__(cls, name, parents, new_attributes)
return type.__new__(cls, name, parents, new_attributes) class Foo(object, metaclass=upper_attr):
bar = 'bip'
def __init__(self):
self.link = "link"
def func(self):
print("Enter func") # 效果与使用函数的元类实现一致!!!
# 类属性,函数都被转换为大写了
print(hasattr(Foo, 'bar')) # False
print(hasattr(Foo, 'BAR')) # True print(hasattr(Foo, 'func')) # False
print(hasattr(Foo, 'FUNC')) # True # 元类转换了类属性,但是没有转换实例属性, __init__ 内的变量没有被转换
print(hasattr(Foo, 'link')) # False
print(hasattr(Foo, 'LINK')) # False print(hasattr(Foo(), 'link')) # True
print(hasattr(Foo(), 'LINK')) # False
4. 写作最后
99%用户用不到元类,所以大家洗洗睡吧,了解就行。
[TimLinux] Python 再谈元类 metaclass的更多相关文章
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- python中的元类metaclass
本文是一个转载的,因为原文写的太好了,所以直接copy过来吧. 原文请看:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上 很热的帖子.提问 ...
- 深刻理解Python中的元类metaclass(转)
本文由 伯乐在线 - bigship 翻译 英文出处:stackoverflow 译文:http://blog.jobbole.com/21351/ 译注:这是一篇在Stack overflow上很热 ...
- 深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- [转] 深刻理解Python中的元类(metaclass)
非常详细的一篇深入讲解Python中metaclass的文章,感谢伯乐在线-bigship翻译及作者,转载收藏. 本文由 伯乐在线 - bigship 翻译.未经许可,禁止转载!英文出处:stacko ...
- 深刻理解Python中的元类(metaclass)【转】
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- 深入理解Python中的元类(metaclass)
原文 译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍 ...
- python——深刻理解Python中的元类(metaclass)
译注:这是一篇在Stack overflow上 很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉 ...
随机推荐
- 利用Python获取统计自己的qq群成员信息
利用python获取自己的qq群成员信息! 首先说明一下需要使用的工具以及技术:python3 + selenium selenium安装方法:pip install selenium 前提:获取自己 ...
- 两张图弄懂函数的递归(以golang为例)
函数递归时要遵守的原则: 执行一个函数时,就要创建一个新的受保护的独立空间(新函数栈) 函数的局部变量是独立的,不会相互影响: 递归必须向退出递归的条件逼近,否则就会无限递归: 当一个函数执行完毕,或 ...
- 篇六:项目使用Dubbo
导语:Dubbo是阿里巴巴的一个分布式服务的开源框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架,每天为2,000+个服务提供3,000,000,000 ...
- SqlServer2005 查询 第六讲 null
今天们来讲sql命令中的这个null参数 null null: 可以理解成[没有值,空值]的意思 注意以下几点 --1.零和null是不一样的,null表示空值,而零表示的一个确定的值 --2.nul ...
- Mybatis动态SQL(where元素、set元素、if元素)
Mybatis动态SQL(where元素.set元素.if元素) - where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句.而且,若语句的开头为“AND”或 ...
- 用maven创建web项目(spring Mvc)
用maven创建web项目(spring Mvc) 1.打开cmd进入到你要创建maven项目的目录下: 2.输入以下命令.然后根据提示输入相应的groupId.artifactId.version: ...
- Zabbix-(六) JMX监控
Zabbix-(六) JMX监控 一.前言 Zabbix提供了JMX监控,它通过JMX API获取JVM信息,从而提供监控数据.本文讲述使用JMX监控Tomcat的JVM信息. 准备 Zabbix S ...
- 力扣(LeetCode)验证回文串 个人题解(C++)
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 示例 1: 输入: "A man, a plan, a c ...
- C语言入门教程: 一个简单的实例
对于学习要保持敬畏! 语言不只是一种工具,还是一种资源,因此,善待它,掌握它! 我们知道,对于未知通常都会充满好奇和畏惧,既想了解它,又害怕神秘面纱隐藏的不确定性.对于一门编程语言同样如此,我将以 ...
- vue引用组件的两个方法
<template> <div> <myComponent></myComponent> </div> </template> ...