`
feisuzhu
  • 浏览: 13896 次
  • 性别: Icon_minigender_1
  • 来自: 济南
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

PyPy中的extendabletype与pairtype解析

 
阅读更多

# -*- coding: utf-8 -*- 

# 首发在 http://page.renren.com/601001752/note/775449636
''' 
PyPy中的extendabletype与pairtype解析 

玩过C#的同学都知道,C#中有一个partial关键字,可以将一个类的实现分在多个文件中,最后由编译器组合起来。这样可以实现多人协作,分离手写和自动生成的代码。 

可能有人会抱怨,为什么Python没有提供这种功能呢?其实是提供了的,只不过比较隐蔽而已——这种问题可以使用元类(metaclass)来解决~ 

什么是元类呢?用一句话来说,元类就是类的类,一般的类是元类的实例。Python下可以使用type(obj)来获得一个变量的类型。type(一个类的实例)会返回那个类,type(一个类)则会返回这个类的元类。在不指明元类的情况下,旧版类的元类是classobj,新版类的元类就是type。这里有一个很有趣的事实:type的元类还是type,type的基类是object,object的元类是type…… 

说了这么多不相关的,到底PyPy的代码是怎样实现partial class的呢? 请看pypy/tool/pairtype.py: 
''' 

class extendabletype(type): 
    """A type with a syntax trick: 'class __extend__(t)' actually extends 
the definition of 't' instead of creating a new subclass.""" 
    def __new__(cls, name, bases, dict): #当创建新类的时候,调用这个函数。此时cls相当与self,不过指的是当前的元类;name是新类的名字;bases是新类的基类;dict是新类的内容,也就是class定义后的那些东西,函数,类变量等等。 
        if name == '__extend__': 
            for cls in bases: 
                for key, value in dict.items(): 
                    if key == '__module__': 
                        continue 
                    # XXX do we need to provide something more for pickling? 
                    setattr(cls, key, value) 
            return None 
        else: 
            return super(extendabletype, cls).__new__(cls, name, bases, dict# 相当于type.__new__(xxxx) 
             
''' 
可以看出,这个元类实现的功能很简单:如果新类的名字是'__extend__',那么不创建新类,而是把新类的dict合并到基类中,这样就相当与扩充了基类! 
举个例子: 
''' 

class MyClass(object): 
    __metaclass__ = extendabletype 
     
    def myprint1(): 
        print "Proton rocks!" 

class __extend__(MyClass): 
    def myprint2(): 
        print "Proton really rocks!" 

#与 

class MyClass(object): 
     
    def myprint1(): 
        print "Proton rocks!" 

    def myprint2(): 
        print "Proton really rocks!" 
         
''' 
是完全一样的! 
知道了这些,就留个小的练习吧: C#中的sealed关键字(不能被继承)在Python中怎么实现呢?只要发现违规用法报错就可以。 

pairtype则是一个更有趣的东西:它的目的是将两个类组合在一起,来作为一个新的类。这么说很容易让人产生误解,还是看源码吧~ 
''' 

def pair(a, b): 
    """Return a pair object.""" 
    tp = pairtype(a.__class__, b.__class__) #根据a和b的类找到相应的pairtype 
    return tp((a, b)) # tp is a subclass of tuple, 根据a和b创建pairtype的实例 

pairtypecache = {} 

def pairtype(cls1, cls2):  
    """type(pair(a,b)) is pairtype(a.__class__, b.__class__).""" 
    try: 
        pair = pairtypecache[cls1, cls2] # 如果pairtype已经存在,就直接返回 
    except KeyError# 如果不存在,就创建一个相应的类 
        name = 'pairtype(%s%s)' % (cls1.__name__, cls2.__name__) 
        bases1 = [pairtype(base1, cls2) for base1 in cls1.__bases__] # 寻找所有的基类,比如pairtype(Human, Girl) 和 pairtype(Boy, Human)就应该是pairtype(Boy, Girl)的基类 
        bases2 = [pairtype(cls1, base2) for base2 in cls2.__bases__] 
        bases = tuple(bases1 + bases2) or (tuple,) # 'tuple': ultimate base 
        pair = pairtypecache[cls1, cls2] = extendabletype(name, bases, {}) # <- 注意是extendabletype,不是type哦 
    return pair 
''' 
恩 这个东西有什么好玩的呢? 在这里举个例子: 
''' 
class Human(object): 
    def __init__(self, name): 
       self.name = name 

class Boy(Human): pass 
class Girl(Human): pass 

class __extend__(pairtype(Human, Human)): 
    def talk((a, b)): # 注意pairtype的基类是tuple, 所以可以直接这样写 
        print "%s and %s are talking." % (a.name, b.name) 

class __extend__(pairtype(Boy, Boy)): 
    def duel((a, b)): 
        print "%s and %s try to prove they are real men, decided to duel." % (a.name, b.name) 

class __extend__(pairtype(Girl, Girl)): 
    def unlimited_talk((a, b)): 
        print "Girls are really scary, %s and %s kept talking for hours without drinking a single gulp of water." % (a.name, b.name) 

class __extend__(pairtype(Boy, Girl), pairtype(Girl, Boy)): 
    def makelove((a, b)): 
        print "%s and %s are... hey you knew it!" % (a.name, b.name) 

reimu = Girl("Reimu") 
marisa = Girl("Marisa") 
moku = Boy("Moku") 
rinnosuke = Boy("Rinnosuke") 

cp1 = pair(reimu, marisa) 
cp1.talk() 
cp1.unlimited_talk() 

cp2 = pair(moku, rinnosuke) 
cp2.talk() 
cp2.duel() 

cp3 = pair(rinnosuke, reimu) 
cp3.talk() 
cp3.makelove()

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics