【问题标题】:Python: Simplify inheritor methodPython:简化继承方法
【发布时间】:2012-10-04 22:07:32
【问题描述】:

我有这样的代码:

class Base:
  def do( self ):
    self._member1 = 0
    self._member2 = 1

class Derived1(Base):
  def do(self):
    Base.do(self)
    self._member3 = 0
    self._member4 = 1

class Derived2(Base):
  def do(self):
    Base.do(self)
    self._member3 = 2
    self._member4 = 3

class Derived3(Base):
  def do(self):
    Base.do(self)
    self._member3 = 9
    self._member4 = 3

等等。这是我所做的:

class Base(object):
  '''Base class.'''
  def do(self):
    self._member1 = 0
    self._member2 = 1

class Derived1(Base): pass
class Derived2(Base): pass
class Derived3(Base): pass
class Derived4(Base): pass

class DerivedFactory(object):
  '''Factory to create derived classes.'''
  members = \
  {
    1: (Derived1, 0, 1),
    2: (Derived2, 4, 5),
    3: (Derived3, 6, 7),
    4: (Derived4, 8, 9),
  }

  def do(self, key=1):
    derived = self.members[key][0]()
    derived.do() # Perform method from Base
    derived._member3 = self.members[key][1]
    derived._member4 = self.members[key][2]
    print(derived)
    print('\t%s' % derived.__dict__)

if __name__ == '__main__':
  factory = DerivedFactory()
  for key in range(1, 5):
    derived = factory.do(key)

但是,它并不像您看到的那样完美。我需要声明 Derived1、Derived2 等。而且它似乎过于复杂。您对如何改进此代码有任何想法吗?谢谢!

【问题讨论】:

    标签: python class inheritance subclass factory


    【解决方案1】:

    据我所知,您只是对减少重复代码感兴趣,这里有一个与您的顶级代码等效的选项:

    class Base:
        def do( self ):
            self._member1 = 0
            self._member2 = 1
    
    def make_do(a, b):
        def do(self):
            Base.do(self)
            self._member3 = a
            self._member4 = b
        return do
    
    class Derived1(Base):
        do = make_do(0, 1)
    
    class Derived2(Base):
        do = make_do(2, 3)
    
    class Derived3(Base):
        do = make_do(9, 3)
    

    Oren 在 cmets 中建议的更短版本(请注意,要使其工作,Base 需要是新样式类):

    class Base(object):
        def do( self ):
            self._member1 = 0
            self._member2 = 1
    
    def make_do(a, b):
        def do(self):
            Base.do(self)
            self._member3 = a
            self._member4 = b
        return do
    
    def make_derived(name, a, b):
        return type(name, (Base,), {'do': make_do(a,b)})
    
    Derived1 = make_derived('Derived1', 0, 1)
    Derived2 = make_derived('Derived2', 2, 3)
    Derived3 = make_derived('Derived3', 9, 3)
    

    这是一个装饰器版本,因为它是在 cmets 中要求的:

    class Base(object):
        def do( self ):
            self._member1 = 0
            self._member2 = 1
    
    def add_do(a, b):
        def do(self):
            Base.do(self)
            self._member3 = a
            self._member4 = b
        def deco(cls):
            return type(cls.__name__, (Base,), {'do': do})
        return deco
    
    @add_do(0, 1)
    class Derived1(Base): pass
    
    @add_do(2, 3)
    class Derived2(Base): pass
    
    @add_do(9, 3)
    class Derived3(Base): pass
    

    另一个装饰器版本,它覆盖子类的do 而不是创建新类型(它还允许您使用旧式类):

    class Base:
        def do( self ):
            self._member1 = 0
            self._member2 = 1
    
    def add_do(a, b):
        def deco(cls):
            original_do = cls.do
            def do(self):
                original_do(self)
                self._member3 = a
                self._member4 = b
            cls.do = do
            return cls
        return deco
    
    @add_do(0, 1)
    class Derived1(Base): pass
    
    @add_do(2, 3)
    class Derived2(Base): pass
    
    @add_do(9, 3)
    class Derived3(Base): pass
    

    【讨论】:

    • 你也可以使用type函数动态创建类: def make_derived(name, a, b): type(name, (Base,), {'do': make_do(a ,b) }) Derived1 = make_derived('Derived1', 0, 1) Derived2 = make_derived('Derived2', 2, 3) Derived3 = make_derived('Derived3', 9, 3)
    • 好建议,已添加到我的答案中。
    • @Oren 确实,它叫metaprogramming :)
    • 在我的答案中添加了一个带有装饰器的版本(不使用元类)。
    • 在最后一种情况下,值得一提的是类装饰器将忽略原始类下的任何其他定义(如果写了其他任何内容而不是pass
    【解决方案2】:

    如果您只是将类用作数据容器,并带有对数据进行操作的方法,那么使用不同的模式可能会更好:

    from collections import namedtuple
    
    Base = namedtuple("Base", ["member1", "member2"])
    Derived = namedtuple("Derived", Base._fields + ("member3", "member4"))
    
    def do(base_or_derived):
    
        print "Member1:", base_or_derived.member1
        print "Member2:", base_or_derived.member2
    
        if not isinstance(base_or_derived, Base):
            print "Member3:", base_or_derived.member3
            print "Member4:", base_or_derived.member4
    
    if __name__ == "__main__":
        base = Base(0, 1)
        derived1 = Derived(0, 1, 0, 1)
        derived2 = Derived(0, 1, 2, 3)
        derived3 = Derived(0, 1, 9, 3)
    
        for item in [base, derived1, derived2, derived3]:
            do(item)
    

    【讨论】:

    • 不行,成员必须只能在do方法中初始化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2018-02-04
    • 1970-01-01
    • 2020-06-27
    • 1970-01-01
    相关资源
    最近更新 更多