3

I am making a python program which is using classes, I want one class to only selectively inherit from another e.g:

class X(object):
    def __init__(self):
        self.hello = 'hello'

class Y(object):
    def __init__(self):
        self.moo = 'moo'

class Z():
    def __init__(self, mode):
        if mode == 'Y':
             # Class will now Inherit from Y
        elif mode == 'X':
             # Class will now Inherit for X

How can I do this without making another class?

1
  • 2
    Can you please give a little more info as to why you want it to be this way? As a design decision it seems a little odd to me, given these bare facts. Commented Sep 19, 2012 at 9:36

4 Answers 4

3

In Python classes can be created at run-time:

class X(object):
    def __init__(self):
        self.hello = 'hello'

class Y(object):
    def __init__(self):
        self.moo = 'moo'

def create_class_Z(mode):
    base_class = globals()[mode]
    class Z(base_class):
        def __init__(self):
            base_class.__init__(self)
    return Z

ZX = create_class_Z('X')
zx = ZX()
print(zx.hello)

ZY = create_class_Z('Y')
zy = ZY()
print(zy.moo)
Sign up to request clarification or add additional context in comments.

Comments

2

You can do this by overriding __new__ and changing the cls passed in (you're creating a new type by appending X or Y as a base class):

class X(object):
    def __init__(self):
        self.hello = 'hello'

class Y(object):
    def __init__(self):
        self.moo = 'moo'

class Z(object):
    def __new__(cls, mode):
        mixin = {'X': X, 'Y': Y}[mode]
        cls = type(cls.__name__ + '+' + mixin.__name__, (cls, mixin), {})
        return super(Z, cls).__new__(cls)
    def __init__(self, mode, *args, **kwargs):
        super(Z, self).__init__(*args, **kwargs)

Note that you need to bypass Z.__new__ using super to avoid infinite recursion; this is the standard pattern for __new__ special override methods.

7 Comments

I think this solution is overly complicated compared to creating the new type in a function outside of class Z, avoiding the infinite recursion pitfall...
@l4mpi it's hardly a pitfall; it's the standard idiom. Writing a __new__ has the advantage of keeping relevant code together and retaining compatibility with existing code.
Writing another function has the advantage of being able to reuse it - my solution is hardcoded to use class Z as the first base class, but you could just put it in a closure with a class and a mapping of base classes and use it for multiple classes. Doing this means you add about two lines of code to every class you want to use in this way - shouldn't be too hard to keep this together with the rest of the code. Also, could you elaborate on the compatibility part?
@l4mpi if your code refers to Z anywhere (e.g. in Z methods with super, in other code accessing static methods or static members, monkeypatching in tests) then all that code expects Z to be the actual class.
@l4mpi also, subclassing Z would break; my solution works absolutely fine for that usage.
|
0

I think you'd better define two members within Z,one is a class instance of X,another is a instance of Y.You can get the associated information stored in these instances while use different mode.

1 Comment

He wants two diferent classes, not two different instances. I don't see how your proposed solution would be of any use.
0

A solution using type:

class _Z(): pass #rename your class Z to this

def Z(mode): #this function acts as the constructor for class Z
    classes = {'X': X, 'Y': Y, 'Foo': Bar} #map the mode argument to the base cls
    #create a new type with base classes Z and the class determined by mode
    cls = type('Z', (_Z, classes[mode]), {})
    #instantiate the class and return the instance
    return cls()

6 Comments

This fails isinstance(Z('X'), Z).
@ecatmur Yes, but you shouldn't use isinstance anyways: canonical.org/~kragen/isinstance
That's out of date; Python has ABC and virtual interfaces now.
@ecatmur I fail to see how that invalidates the criticisms of isinstance compared to the EAFP approach... but anyways, you could just use isinstance(Z('X'), _Z) if it is absolutely needed.
PEP 3119 discusses where interfaces and virtual subclasses are superior to EAFP. My real point was that you're violating the basic assumption that Z is a class.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.