菜单

Python基础(玖) type元类

2019年4月9日 - 金沙编程资讯

python元类:**type()   **

 

 

Python 中 Meta Classes详解,pythonclasses

接触过 Django 的校友都应当相当耳熟能详它的 OLANDM 系统。对于 python
新手而言,那是1项大约能够被称作“黑科学和技术”的性状:只要你在models.py中不管定义一个Model的子类,Django
便足以:

  1. 赢得它的字段定义,并更换来表结构
  2. 读取Meta内部类,并转化成相应的布局信息。对于分外规的Model(如abstract、proxy),还要开始展览对应的变换
  3. 为未有定义objects的Model加上一个暗中同意的Manager

开发之余,作者也曾脑补过其幕后的法则。曾经,小编认为是这么的:

运转时,遍历models.py中的全部属性,找到Model的子类,并对其进行上述的改动。
当时,笔者还以为本人触蒙受了真理,并曾将其选取到实在生产中——为 SAE 的 KVDB
写了一个类 OTiggoM
系统。可是在达成的进程中,作者肯定感受到了那种办法的丑陋,而且质量并不好看(因为要遍历全体的概念模块)。

那么实际上,Django 是怎么落到实处的啊?

自古以来我们制造东西的方法都是“自上而下”的,是用切削、分割、组合的方法来制造。然而,生命是自下而上地,自发地建造起来的,这个过程极为低廉。
——王晋康 《水星播种》

那句话揭穿了人命的神奇所在:真正的生命都以由基本物质自发组成的,而非造物主流水生产线式的加工。

那便是说,若是 类
也有人命来说,对它和谐的梳洗就不应当由调用者来实现,而应该是纯天然的。

幸好,python 提供了上帝的接口——那正是 Meta Classes,或许叫做“元类”。

元类 是什么?

概括说:元类正是类的类。

第二,要有贰个定义:

python 中,1切都是对象。

没错,一切,包括 类 本身。

既然如此,类 是 对象,对象 是 类的实例,那么——类 也理应有 类 才对。

类的类:type

在 python 中,大家得以用type检验多少个目的的类,如:

print type(1) # <type 'int'>

壹旦对多少个类操作呢?

print type(int) # <type 'type'>

class MyClass(object): pass

print type(MyClass) # <type 'type'>

print type(type) # <type 'type'>

那注脚:type其实是1个体系,全体类——包涵type自个儿——的类都以type。

type 简介

从 官方文书档案 中,我们能够领略:

和 dict 类似,type 也是几个工厂构造函数,调用其将重回一个type类型的实例(即 类)。
type 有多少个重载版本:

下边多个语句等价:

class Integer(int):

  name = 'my integer'

  def increase(self, num):
    return num + 1

  # -------------------

  Integer = type('Integer', (int, ), {
  'name': 'my integer',
  'increase': lambda self, num: \
          num + 1  # 很酷的写法,不是么
  })

也便是说:类的定义进度,其实是type类型实例化的经过。

但是那和修饰一个已定义的类有怎么着关联吧?

当然有啦~既然“类的概念”正是“type类型的初始化进度”,这里边必定会调用到type的构造函数(__new__()
或 __init__())。只要大家接二连三 type类 并修改其
__new__函数,个中动手脚就能够啊。

接下去我们将由此贰个板栗感受 python
的黑魔法,不过之前,大家要先了然三个语法糖。

__metaclass__ 属性

有没觉着上边第二段示例有个别鬼畜呢?它勒令程序员将类的分子写成三个字典,大致是反人类。假设大家确实是要由此改动
元类 来改变 类 的行为的话,就像就不可能不运用那种艺术了~~简直可怕~~

万幸,python 二.二 时引进了四个语法糖:__metaclass__澳门金沙js333,。

class Integer(int):

  __metaclass__ = IntMeta

明日将会等价于:

Integer = IntMeta('Integer', (int, ), {})

由此1来,我们在行使守旧类定义的还要,也能够动用元类啦。

栗子:子类净化器

金沙91590.com,要求描述

澳门金沙官网,你是二个有语言洁癖的开发者,日常容不得别人讲一句脏话,在付出时也是那样。未来,你写出了二个特别棒的框架,并立刻要将它公之于众了。可是,你的失眠又犯了:倘诺你的使用者在代码中写满了脏话,如何做?岂不是玷污了本人的高洁?
比方你就是其壹丧心病狂的开发者,你会如何做?

在明亮元类以前,你也许会无从入手。可是,那一个标题你能够用 元类
轻松化解——只要在类定义时过滤掉不到头的单词就好了(百度贴吧的工作~~)。

咱俩的元类看起来会是这般的:

sensitive_words_list = ['asshole', 'fuck', 'shit']

def detect_sensitive_words(string):
  '''检测敏感词汇'''
  words_detected = filter(lambda word: word in string.lower(), sensitive_words_list)

  if words_detected:
    raise NameError('Sensitive words {0} detected in the string "{1}".' \
      .format(
        ', '.join(map(lambda s: '"%s"' % s, words_detected)),
        string
      )
    )

class CleanerMeta(type):

  def __new__(cls, class_name, bases, attrs):
    detect_sensitive_words(class_name) # 检查类名
    map(detect_sensitive_words, attrs.iterkeys()) # 检查属性名

    print "Well done! You are a polite coder!" # 如无异常,输出祝贺消息

    return super(CleanerMeta, cls).__new__(cls, class_name, bases, attrs)
    # 重要!这行一定不能漏!!这回调用内建的类构造器来构造类,否则定义好的类将会变成 None
现在,只需这样定义基类:

class APIBase(object):

  __metaclass__ = CleanerMeta

  # ...
那么所有 APIBase 的派生类都会接受安全审查(奸笑~~):

class ImAGoodBoy(APIBase):

  a_polite_attribute = 1

# [Output] Well done! You are a polite coder!

class FuckMyBoss(APIBase):

  pass

# [Output] NameError: Sensitive words "fuck" detected in the string "FuckMyBoss".

class PretendToBePolite(APIBase):

  def __fuck_your_asshole(self):
    pass

# [Output] NameError: Sensitive words "asshole", "fuck" detected in the string "_PretendToBePolite__fuck_your_asshole".

看,即便像尾数事例中的私有属性也难逃审查,因为它们本质都以平等的。

照旧,你还足以对有难点的性质实行专断的修改,比如
让不文明的函数在调用时打出一行警告 等等,那里就不多说了。

元类 在事实上支付中的应用

平凡成本时,元类 常用吗?

本来,Django 的 O福睿斯M 正是二个例子,如雷贯耳的 SQLAlchemy
也用了那种黑魔法。

其它,在局地小型的库中,也有 元类 的身材。比如
abc(奇怪的名字~~)——那是 python 的2个内建库,用于模拟
抽象基类(Abstract Base Classes)。开发者能够动用 abc.abstractmethod
装饰器,将 钦点了 __metaclass__ = abc.ABCMeta 的类的点子定义成
抽象方法,同时那几个类也成了
抽象基类,抽象基类是不可实例化的。那便完成了对 抽象基类 的模拟。

假若你也有亟待动态修改类定义的须求,不要紧也尝试那种“黑魔法”。

小结

  1. 类 也是 对象,全部的类都是type的实例
  2. 元类(Meta Classes)是类的类
  3. __metaclass__ = Meta 是 Meta(name, bases, dict) 的 语法糖
  4. 能够经过重载元类的 __new__ 方法,修改 类定义 的行为

元类是python高阶语法.
合理的选取能够收缩大气重复性的代码.

1      引子

1      引子

你可能感兴趣的文章:

中 Meta Classes详解,pythonclasses 接触过
Django 的同校都应当特别熟练它的 O瑞虎M 系统。对于 python
新手而言,这是一项差不多可以被称作“黑科…

 

1.1     神奇的Django中的models

咱俩先来看1段在Django项目中常用的代码:

设置数据库models代码:

class Students(models.Model):
    name = models.CharField()
    age = models.IntegerField()

那边有多少个神奇的地方,涉及到了python中最神秘的多少个脾气。

先看下有啥样神奇的地方:

此间用的是python的三个语法性子:

我们来一步一步解开神秘面纱。

1.1     神奇的Django中的models

咱俩先来看一段在Django项目中常用的代码:

设置数据库models代码:

class Students(models.Model):
    name = models.CharField()
    age = models.IntegerField()

那里有多少个神奇的地方,涉及到了python中最神秘的多少个特点。

先看下有哪些神奇的地方:

此地用的是python的三个语法天性:

大家来一步一步解开神秘面纱。

元类实际上做了以下3方面包车型地铁办事:

2      数据校验

2      数据校验

 

二.一     数据校验难题

Python即使是强类型的脚本语言,可是在概念变量时却不能够内定变量的门类。

比如说,大家在Student类中定义二个age字段,合法值一般为包蕴0的正整数,但是在python中无正整数的种类,只可以协调来校验。

class Student:
    def __init__(self, name, age):
        if isinstance(name,str):
            self.name = name
        else:
            raise TypeError("Must be a string")

        if isinstance(int, age):
            self.age = age
        else:
            raise TypeError("Must be an int")

 

而是,假诺更新禧龄时就会遇见标题,不能够重用校验逻辑。

有未有简短的法子呢?

贰.壹     数据校验难题

Python纵然是强类型的脚本语言,但是在概念变量时却不能够钦命变量的类型。

诸如,大家在Student类中定义二个age字段,合法值一般为包涵0的正整数,不过在python中无正整数的档次,只好自个儿来校验。

class Student:
    def __init__(self, name, age):
        if isinstance(name,str):
            self.name = name
        else:
            raise TypeError("Must be a string")

        if isinstance(int, age):
            self.age = age
        else:
            raise TypeError("Must be an int")

 

但是,借使更新岁龄时就会蒙受难点,不可能重用校验逻辑。

有未有简短的艺术吗?

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图