zoukankan      html  css  js  c++  java
  • Python使用装饰器自动调用父类__init__

      众所周知,Python中class的构造函数实际是__new__(),但是如果我们执行p1=Point()的时候,不仅会调用Point的__new__方法,而且会调用Point的__init__方法。由于python中所有都是对象,而所有对象的基类都是继承自object,而object实现的__new__基本都满足所有自定义类的要求,所以一般情况下,我们无需重新实现__new__,而只是关注__init__的实现,比如要初始化属性等都放在__init__中。python的这种机制直接导致,如果我们在父类的__init__中实现了一些逻辑,但是子类中又要遵循这些逻辑,就必须显式调用super(cls,self).__init__,在大量的自定义类中来显式调用父类的__init__,让人非常不爽。于是想,有没有一种方法可以让子类能自动隐式调用父类的__init__方法呢?

       首先,想到的是python中的装饰器,能用装饰器来实现,最方便不过了,但这里需要解决2个问题:

      1)p1=Point(),Point的__new__与__init__都会执行,我们必须将两者分开,能独立执行:创建Point的实例,调用super().__init__,再调用self.__init__

      2)装饰器必须返回真实的实例:而不是其它对象

      具体实现代码如下:

    #使用装饰器自动调用父类的无参__init__方法
    def super_init_wrapper(origin_cls):
        super_class=origin_cls.mro()[1]
        class WrapperClass:
            def __new__(cls,*args,**kwargs):
                #print('origin class',origin_cls)
                instance= object.__new__(origin_cls,*args,**kwargs)
                super_class.__init__(instance)
                instance.__init__(*args,**kwargs)
                return instance
        return WrapperClass
    
    class Base:
        def __init__(self):
            self.x=100
            print('Base init')
            
    @super_init_wrapper
    class Instance(Base):
        def __init__(self,a,b,c):
            self.a=a
            self.b=b
            self.c=c
            print('Instance init')
    
    if __name__=='__main__':
        ins=Instance('a','b','c')
        #ins= super_init_wrapper(Instance)('a','b','c')
        print(isinstance(ins,Base))
        print(type(ins))
        print(ins.x)
    import inspect
    #kcargs的格式super参数名=self参数名的形式,比如x='{x}'
    def auto_super_initial(**kcargs):
        def decrorate(self_cls):
            base_cls=self_cls.mro()[1]
            class DecorateClass:
                def __new__(cls,*args,**kwargs):
                    self=object.__new__(self_cls,*args,**kwargs)
                    sig=inspect.signature(self.__init__)
                    init_args=sig.bind_partial(*args,**kwargs).arguments
                    #构造调用super.__init__的参数
                    super_args={name:eval(str(value).format(**init_args)) for name,value in kcargs.items()}
                    base_cls.__init__(self,**super_args)
                    self_cls.__init__(self,*args,**kwargs)
                    return self
            return DecorateClass
        return decrorate
        
    
    class Point:
        def __init__(self,x=0,y=0):
            self.x=x
            self.y=y
    
    class Line(Point):
        def __init__(self,x=0,y=0,length=0):
            super(Triangle,self).__init__(x,y)
            self.length=length
            
    @auto_super_initial(x='{x}+{y}',y='{y}')
    class Rectangle(Point):
        def __init__(self,x=0,y=0,width=0,height=0):
            self.width=width
            self.height=height
    
    if __name__=='__main__':
        rect=Rectangle(1,10,10,10)
        print(rect.x,rect.y) #11 10
  • 相关阅读:
    HDOJ 1207 汉诺塔II
    [转]写代码的小女孩
    POJ Subway tree systems
    HDOJ 3555 Bomb (数位DP)
    POJ 1636 Prison rearrangement (DP)
    POJ 1015 Jury Compromise (DP)
    UVA 10003
    UVA 103 Stacking Boxes
    HDOJ 3530 Subsequence
    第三百六十二、三天 how can I 坚持
  • 原文地址:https://www.cnblogs.com/lane_yang/p/10701986.html
Copyright © 2011-2022 走看看