元类和动态类

本篇笔记学习自:Improve Your Python: Metaclasses and Dynamic Classes With Type

  • type()的使用
>>> type(1)
<class 'int'>
>>> type('foo')
<class 'str'>
>>> type(3.0)
<class 'float'>
>>> type(float)
<class 'type'>
  • type的类型?
    上面的 type(float) 为什么是<class 'type'>呢?我们再来看一个例子:
>>> class Foo(object):
...     pass
...
>>> type(Foo)
<class 'type'>

还有这个:

>>> type(type)
<class 'type'>

type是所有类型的类型,包括它自己。type是一个元类,或者是一个创建所有类的东西。

  • 创建自己的元类

Just like regular classes, metaclasses can be user-defined. To use it, you set a class's metaclass attribute to the metaclass you built. A metaclass can be any callable, as long as it returns a type. Usually, you'll assign a class's metaclass to a function that, at some point, uses a variant of type we've not yet discussed: the three parameter variety used to create classes.

就像普通的类,元类也可以是用户自定义的。使用自定义元类时,你需要设置一个类的metaclass属性为你创建的那个元类。元类可以是任何可调用的函数,只要它返回一种类型。

当我们写下下面的代码就是创建类的过程,首先解释器会检查是否有metaclass这个属性,没有就调用type来创建类(类也是对象)。

class Foo(Bar):
  pass

现在的问题就是,你可以在metaclass中放置些什么代码呢?答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东东都可以。

  • type的缺点
    当我们调用type并且传入三个参数的时候——type(name, bases, dict)创建一种新的类型。
    以下的两份代码作用是相同的,运行后,Foo都指向了一个继承自object的类:
class Foo(object):
    pass
Foo = type('Foo', (), {})

添加方法:

def always_false(self):
    return False

Foo.always_false = always_false

或者可以这样子做:

Foo = type('Foo', (), {'always_false': always_false})

类的继承:

FooBar = type('FooBar', (Foo), {})
  • 这有什么鬼用?
    虽然不经常用到,但是在一些场合,用type来创建类比较合适,比如在一些需要动态创建类的场合,只有程序允许起来,我们才有足够的信息知道要怎么去创建类,这些场合用type来动态创建类比较合适。

元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过在模块级别设定metaclass。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。

  • 自定义元类的例子——将类的属性都改为大写

元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为API做这样的事情,你希望可以创建符合当前上下文的
类。假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通
过在模块级别设定metaclass。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有
的属性都改成大写形式就万事大吉了。

首先我们需要一个元类:

# 元类会自动将你通常传给‘type’的参数作为自己的参数传入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    '''返回一个类对象,将属性都转为大写形式'''
     # 选择所有不以'__'开头的属性
     attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
     #  将它们转为大写形式
    uppercase_attr = dict((name.upper(), value)  for name, value  in attrs)
     #  通过 'type' 来做类对象的创建
     return type(future_class_name, future_class_parents, uppercase_attr)

模块级别地设置metaclass

__metaclass__ = upper_attr   #   这会作用到这个模块中的所有类
class Foo(object):
     #  我们也可以只在这里定义 __metaclass__ ,这样就只会作用于这个类中
    bar = 'bip'
    print
    hasattr(Foo, 'bar')
    #  输出 : False
    print
    hasattr(Foo, 'BAR')
    #  输出 :True
    f = Foo()
    print
    f.BAR
    #  输出 :'bip'

拓展阅读:
1.stackoverflow上面的问答
2.上面链接回答的翻译

类也是对象,创建类的就是元类。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 136,465评论 19 139
  • 前言 第十二篇了,撸起袖子,就是干。 目录 一、Python 中类也是对象 在了解元类之前,我们先进一步理解 Py...
    GitHubClub阅读 839评论 0 7
  • { "Unterminated string literal.": "未终止的字符串文本。", "Identifi...
    栗子雨阅读 8,068评论 0 3
  • 1.元类 1.1.1类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这...
    TENG书阅读 1,417评论 0 3
  • 一元类 1类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这一点仍然成...
    五行缺觉阅读 1,156评论 0 1

友情链接更多精彩内容