Python : How to “merge” two class

2019-04-28 20:35发布

I want to add some attributes and methodes into various class. The methodes and attributes that I have to add are the same but not the class to assign them, so I want to construct a class who assign new methodes and attribute for a class given in argument. I try this but it's not working: (I know that is a very wrong way to try to assign something to self, it's just to show what I want to do)

class A:
    def __init__(self):
        self.a = 'a'

    def getatt(self):
        return self.a

class B:
    def __init__(self, parent) :
        self = parent

        # This is working :
        print self.getatt()

    def getattB(self):
        return self.getatt()

insta = A()
instb = B(insta)

# This is not working :
print instb.getattB()

The result is :

a
Traceback (most recent call last):
  File "D:\Documents and settings\Bureau\merge.py", line 22, in <module>
    print instb.getattB()
  File "D:\Documents and settings\Bureau\merge.py", line 16, in getattB
    return self.getatt()
AttributeError: B instance has no attribute 'getatt'

And I expected to got 'a' for the call of instb.gettattB()

To resume I want to inherit class B from class A giving class A in argument of class B because my class B will be a subclass of various class, not always A.

5条回答
何必那么认真
2楼-- · 2019-04-28 21:02

Since B is not a subclass of A, there is no path in B to getatt() in A

查看更多
放我归山
3楼-- · 2019-04-28 21:07

I was having trouble with calling different constructors, using super doesn't necessarily make sense in a case like this, I opted to inherit and call each constructor on the current object manually:

class Foo(object):
    def __init__(self, foonum):
        super(Foo, self).__init__()
        self.foonum = foonum


class Bar(object):
    def __init__(self, barnum):
        super(Bar, self).__init__()
        self.barnum = barnum

class DiamondProblem(Foo, Bar):
    # Arg order don't matter, since we call the `__init__`'s ourself.
    def __init__(self, barnum, mynum, foonum):
        Foo.__init__(self, foonum)
        Bar.__init__(self, barnum)

        self.mynum = mynum
查看更多
Fickle 薄情
4楼-- · 2019-04-28 21:11

The Best answer is in the comments, it was useful for me so I decided to show it in an answer (thank to sr2222): The way to dynamicaly declare inherance in Python is the type() built-in function. For my example :

class A(object) :
    def __init__(self, args):
        self.a = 'a'
        self.args = args

    def getattA(self):
        return self.a, self.args

class B(object) :
    b = 'b' 
    def __init__(self, args) :
        self.b_init = args

    def getattB(self):
        return self.b

C = type('C', (A,B), dict(c='c'))

instc = C('args')

print 'attributes :', instc.a,  instc.args, instc.b, instc.c
print 'methodes :', instc.getattA(), instc.getattB()

print instc.b_init

The code return :

attributes : a args b c
methodes : ('a', 'args') b
Traceback (most recent call last):
  File "D:\Documents and settings\Bureau\merge2.py", line 24, in <module>
    print instc.b_init
AttributeError: 'C' object has no attribute 'b_init'

My class C inerhite attributes and methods of class A and class B and we add c attribute. With the instanciation of C (instc = C('args')) The init for A is call but not for B.

Very useful for me because I have to add some attributes and methodes (the same) on different class.

查看更多
ら.Afraid
5楼-- · 2019-04-28 21:12

How about this?

class A:
    def __init__(self):
        self.a = 'a'

    def getatt(self):
        return self.a

class B:
    def __init__(self, parent) :
        self.parent = parent

    def __getattr__(self, attr):
        return getattr(self.parent, attr)

    def getattB(self):
        return self.parent.getatt()

insta = A()
instb = B(insta)

print instb.getattB()
print instb.getatt()

But method in class A can not access attr in class B.

Another way:

import functools
class A:
    def __init__(self):
        self.a = 'a'

    def getatt(self):
        return self.a

class B:
    def __init__(self, parent):
        for attr, val in parent.__dict__.iteritems():
            if attr.startswith("__"): continue
            self.__dict__[attr] = val
        for attr, val in parent.__class__.__dict__.iteritems():
            if attr.startswith("__"): continue
            if not callable(val): continue
            self.__dict__[attr] = functools.partial(val, self)

    def getattB(self):
        return self.getatt()

insta = A()
instb = B(insta)

print instb.__dict__
print instb.getattB()
print instb.getatt()

Slow with init but call fast.

查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-04-28 21:20

I'm not certain what you are trying to do, but the code below is giving my the output I think you are expecting. notice:

  1. a is initialized outside the constructor in A
  2. B is declared as a subclass of A

Code:

class A:
    a='' #Initialize a

    def __init__(self):
        self.a = 'a'

    def getatt(self):
        return self.a

class B(A):  #Declare B as subclass
    def __init__(self, parent) :
        self = parent

        print self.getatt()

    def getattB(self):
        return self.getatt()

insta = A()
instb = B(insta)

print instb.getattB()
查看更多
登录 后发表回答