python元类的概念_Python中的元类编程 | 学步园

过去有这样的概念,一直没有深究它的意义.今天同事问到,刚好也好好了解下.

#===============================================Python中的元类编程===============================================

#淆元类和基类的不同。从“定义”类的表面上来区分,两者看上去是类似的。可一旦深入下去,两个概念就区别开来。

#在举例之前,明确一些术语是非常有意义的。

#实例 是由类“制造”的 Python 对象;类充当实例的一种模版。每一个实例只能属于一个类(但一个类可以有多个实例)。

#我门经常说的实例对象――或“简单实例”――是“最终的”,即意味着不能作为其他对象的模版(但它仍然可能是一个 工厂或 代表,这二者的目的有重叠)。

#某些实例对象就是类本身,并且所有的类都是相应 元类的实例,甚至类也只能通过实例化机制生成。

#通常,类是内建的标准的元类 type 的实例;只有当我们指定元类而不是指定 type 时,才需要考虑元类编程。我们也称用来实例化对象的类为那个对象的 类型。

#运行实例化想法的 正交是继承的概念。这里,一个类可以有一个或多个父亲,而不是只有一个惟一的类型。

#并且父亲还可以有父亲,创建一个传递的子类关系后,可以方便地利用内建的 issubclass() 函数来判断继承关系。

#例如,如果我们定义一些类和一个实例:

#代码清单 1. 典型的继承层次

class A(object):

a1 = 'A'

class B(object):

a2 = 'B'

class C(A, B):

a3 = 'C(AB)'

class D(C):

a4 = 'D(C)'

#然后我们可以测试这些关系:

d = D()

d.a5 = "instance d of D"

print d.a5

#输出结果:instance d of D

#代码清单 2. 测试祖先

print issubclass(D,C)

#输出结果:True

print issubclass(D,A)

#输出结果:True

print issubclass(A,B)

#输出结果:False

#print issubclass(d,D)

#输出结果:TypeError: issubclass() arg 1 must be a class

#现在,一个很有趣的问题——理解超类与元类的不同所必需的一个问题——是像 d.attr 这样的属性是如何被解析的。

#简单起见,我们只讨论标准的查找规则,而不是回到 .__getattr__() 。

#这个解决方案的第一步是在 d.__dict__ 中查找名字 attr ,如果找到了,那么就是它,但如果不是,一些有趣的事情将会发生,

#例如:

print d.__dict__

#输出结果:{'a5': 'instance d of D'}

print d.a5

#输出结果:instance d of D

print d.a1

#输出结果:A

#查找一个不与实例关联的属性时有一个技巧,即先在实例的类中查找,然后再在从所有的超类中查找。

#这一过程中父类被检查的顺序被称为这个类的 方法解析顺序,您可以利用以下这个(元)方法 .mro()

#看出该顺序 (但只能是从类对象中看到):

print  [k.__name__ for k in d.__class__.mro()]

#输出结果:['D', 'C', 'A', 'B', 'object']

#换句话说,访问 d.attr 时首先是在 d.__dict__ 中,然后在 D.__dict__ , C.__dict__ , A.__dict__ , B.__dict__ ,

#最后才是在 object.__dict__ 中查找,如果在任意一个地方都未找到这个名字,就会产生一个 AttributeError 。

#注意,从未在查找过程中提到过元类。

print "----------------------------------------------------------------------------------------------------------------"

#===============================================元类与祖先===============================================

#这里有一个普通的继承的简单例子,我们定义了一个 Noble 基类,它有子类 Prince , Duke , Baron 等等。

#代码清单 3. 属性继承

for s in "Power Wealth Beauty".split(): exec '%s="%s"'%(s,s)

# ...in fairy tale world

class Noble(object):

attributes = Power, Wealth, Beauty

class Prince(Noble):

pass

print Prince.attributes

#输出结果:('Power', 'Wealth', 'Beauty')

#类 Prince 继承了 Noble 的属性, Prince 类的实例仍然遵循上述的查找链。

#代码清单 4. 实例中的属性

charles=Prince()

print charles.attributes

#输出结果:('Power', 'Wealth', 'Beauty')

print "----------------------------------------------------------------------------------------------------------------"

#如果 Duke 碰巧有一个定制元类,那么它能够以以下方式获得一些属性:

class Nobility(type):

attributes = Power, Wealth, Beauty

class Duke(object):

__metaclass__ = Nobility

#Duke是一个类,也是元类 Nobility 的一个实例——属性的查找过程与其他对象一致:

print Duke.attributes

#但是 Nobility 不是 Duke 的超类,所以这就是为什么 Duke 的 实例会找到 Nobility.attributes 的原因:

#代码清单 5. 属性与元类

print Duke.mro()

#输出结果:[, ]

earl = Duke()

#print earl.attributes

#输出结果:AttributeError: 'Duke' object has no attribute 'attributes'

#元类属性的可用性是不会传递的,也就是说,元类的属性是对它的实例是可用的,

#但是对它的实例的实例是不可用的。这正是元类与超类的主要不同。下图强调了继承与实例化的异同。

#图 1. 实例化与继承

#                                               Nobility

#                                                    |

#                                                    |

#        Noble----->Prince            V

#                     |                          Duke

#                     |                             |

#                     V                            |

#                   charles                  V

#                                                 earl

#

#因为 earl 仍然有一个类,因而您可以间接地得到其属性:

print earl.__class__.attributes

#输出结果:('Power', 'Wealth', 'Beauty')

#图1对比了只涉及继承或是元类的简单情况,而不是同时涉及的情况。但有些时候,一个类 C 同时有定制元类M和基类 B:

#代码清单 6. 结合元类与超类

class M(type):

a = 'M.a'

x = 'M.x'

class N(object):

a = 'N.a'

class P(N):

__metaclass__ = M

p=P()

#图 2. 超类与元类的结合

#                            M(M.a)

#                                |

#                                |

#                               V

#      N(N.a)------->P(?)

#                               |

#                               |

#                              V

#                            p(?)

#

#根据前面的解释,我们能够想像 P.a 将解析成 M.a 或 N.a 。当解析发生时,在查找实例化元类之前,会先遵循它的 mro() 对类进行查找。

#代码清单 7. 解析元类与超类

print P.a,P.x

#输出结果:N.a M.x

print p.a

#输出结果:N.a

#print p.x

#输出结果:AttributeError: 'P' object has no attribute 'x'

#您仍然可以使用元类来增强属性,只需在被实例化的类对象上进行设置,而不是像元类的属性那样。

#清单 8. 在元类中设置属性

class M2(type):

def __init__(cls, *args):

cls.a = 'M2.a'

class P2(N):

__metaclass__= M2

print P2.a, P2().a

#输出结果:M2.a M2.a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值