mixin class

Discussion in 'Python' started by Udo Gleich, Jul 28, 2003.

  1. Udo Gleich

    Udo Gleich Guest

    Hi,

    I try to implement mixin classes. Thats why I
    need to make a new class at runtime.

    --tmp.py-------------------------------------

    import new

    class K1(object):
    pass

    class K2(object):
    pass

    mixed = new.classobj("K1_K2", (K1, K1), {})
    new_instance = new.instance(mixed, {})

    print new_instance

    ---------------------------------------------

    Making a new instance from the new class works
    only if K1 is not derived from object. If I use
    new style classes I get the following traceback:

    Traceback (most recent call last):
    File "tmp.py", line 10, in ?
    new_instance = new.instance(mixed, {})
    TypeError: instance() argument 1 must be class, not type

    I use Python 2.2.3 and Win2000.

    My question: How do I implement mixin classes
    with new style classes?

    Thanks,

    Udo
     
    Udo Gleich, Jul 28, 2003
    #1
    1. Advertising

  2. Udo Gleich <> wrote in message news:<>...
    > Hi,
    >
    > I try to implement mixin classes. Thats why I
    > need to make a new class at runtime.
    >
    > --tmp.py-------------------------------------
    >
    > import new
    >
    > class K1(object):
    > pass
    >
    > class K2(object):
    > pass
    >
    > mixed = new.classobj("K1_K2", (K1, K1), {})
    > new_instance = new.instance(mixed, {})
    >
    > print new_instance
    >
    > ---------------------------------------------
    >
    > Making a new instance from the new class works
    > only if K1 is not derived from object. If I use
    > new style classes I get the following traceback:
    >
    > Traceback (most recent call last):
    > File "tmp.py", line 10, in ?
    > new_instance = new.instance(mixed, {})
    > TypeError: instance() argument 1 must be class, not type
    >
    > I use Python 2.2.3 and Win2000.
    >
    > My question: How do I implement mixin classes
    > with new style classes?
    >
    > Thanks,
    >
    > Udo


    Why not simply

    class K1(object):
    pass

    class K2(object):
    pass

    mixed = type("K1_K2", (K1, K1), {})
    new_instance = mixed()

    print new_instance

    ?

    "type" is described in http://www.python.org/2.2.3/descrintro.html
    (in one line very easy to miss ;)


    Michele
     
    Michele Simionato, Jul 28, 2003
    #2
    1. Advertising

  3. Udo Gleich

    Udo Gleich Guest

    Hi,

    > Why not simply
    >
    > class K1(object):
    > pass
    >
    > class K2(object):
    > pass
    >
    > mixed = type("K1_K2", (K1, K1), {})
    > new_instance = mixed()
    >
    > print new_instance
    >


    almost.

    If K1 has a constructor that takes arguments you get an
    error when you call the constructor of the derived class
    without an argument. Why do I want to do that? Usually
    one would say that I should know the arguments of the
    constructor of the derived class.

    What I want to do is take *two objects*, derive from both
    their classes, make a new object and combine the state of
    the old objects.

    I dont know if that is a good idea. I would appreciate comments
    on the following solution. Especially the use of the dummy_init
    function as an empty constructor looks not quite right to me.

    ---------------------------------------------------------------------

    def dummy_init(self):
    pass

    class Mixin:

    __shared_state = {"classes":{}}

    def __init__(self):
    self.__dict__ = self.__shared_state

    def mix(self, original_instance, mixin_instance):
    original_class = original_instance.__class__
    mixin_class = mixin_instance.__class__
    name = original_class.__name__ + '_' + mixin_class.__name__
    mixed = self.classes.get(name,
    type(name,
    (mixin_class, original_class),
    {"__init__": dummy_init}))
    new_instance = mixed()

    new_instance.__dict__.update(mixin_instance.__dict__)
    new_instance.__dict__.update(original_instance.__dict__)

    try:
    new_instance.late_init_original()
    except AttributeError:
    pass
    try:
    new_instance.late_init_mixin()
    except AttributeError:
    pass
    return new_instance

    class K1(object):
    def __init__(self, a):
    self.a = a

    class K2(object):
    def late_init_mixin(self):
    self.b = self.a + 1


    mixer = Mixin()

    new_instance = mixer.mix(K1(3), K2())

    print new_instance
    print new_instance.a, new_instance.b

    -------------------------------------------------------------------------
     
    Udo Gleich, Jul 29, 2003
    #3
  4. Udo Gleich

    Udo Gleich Guest

    > > mixed = new.classobj("K1_K2", (K1, K1), {})

    There is an error in the code. Obviously it should
    read

    mixed = new.classobj("K1_K2", (K1, K2), {})
    --
     
    Udo Gleich, Jul 29, 2003
    #4
  5. Udo Gleich <> wrote in message news:<>...
    > What I want to do is take *two objects*, derive from both
    > their classes, make a new object and combine the state of
    > the old objects.
    >
    > I dont know if that is a good idea. I would appreciate comments
    > on the following solution. Especially the use of the dummy_init
    > function as an empty constructor looks not quite right to me.


    You may avoid dummy_init and have the default object.__init__ but
    this is not the point. The whole construction seems ugly to me.
    Do you have the option of using only class variables ? I mean, no
    explicit instance dictionary? Then you could simply create the
    mixin from the original classes and not merge by hand the
    instance dictionaries. Do you have the option of modifying the
    original classes to make the all structure more multiple inheritance
    friendly? The idea is that one should derive objects from classes,
    not classes from objects. What you are doing will probably work,
    but It is quite ugly to me.I cannot say more if I have no idea of what
    are your constraints. If you cannot touch the original classes,
    remember that you can create modifications of them, as mixin-frendly
    as you wish. I also have a question: why don't you override the
    __init__ method in M in such a way that it calls K1.__init__ and
    K2.__init__ according to the number of arguments? That would be
    the first thing would come to my mind, but maybe you have reasons
    why you don't want that.
    HTH,


    Michele
     
    Michele Simionato, Jul 29, 2003
    #5
  6. On Mon, 28 Jul 2003 12:20:02 +0200, Udo Gleich wrote:
    > My question: How do I implement mixin classes
    > with new style classes?


    Um, if I understand what you're trying to do correctly, it's easy:

    --------------
    import random

    class A(object): pass
    class B(object): pass
    class C(object): pass
    class D(object): pass

    mixin = random.choice([C, D])

    class A_B_and_C_or_D(A, B, mixin): pass

    newName = A_B_and_C_or_D

    newInstance = newName()
    ----------------

    (Warning: Didn't actually type this in)

    The classes being derived from can be variable; in fact I do this rather
    too frequently for my own good, perhaps. (I tend to use it for class I
    want to be intimately involved with each other, but also usable
    separately, having one of them dynamically derive from either object or
    the other class, depending on whether the other class is available.)

    So in this example, on any given run, class A_B_and_C_or_D will always
    derive from A and B, and may derive from either of C or D.

    You can dynamically do this in a loop or something if you're feeling
    creative, if you assign the class to new names, as I did here for
    "newName". AFAIK there's no way to programmatically create new classes
    with generated names without resorting to eval (bad idea), but you can
    bind them to new names after creation and that works OK.

    ----------------

    classesILike = {}
    for i in range(10):
    class tmp(object): pass
    classesILIke = tmp

    ----------------

    and of course "tmp" may derive from what it will.

    The inheritance list is as dynamic as anything else in Python; feel free
    to use it that way. Personally I find this is a "killer feature"... you'd
    find it hard to describe in advance when you'd want it, but when
    you want it, you want it ***badly***, because the kludge will be a
    killer... and there are very, very few languages that can do this cleanly
    (and still share Python's other benefits).
     
    Jeremy Bowers, Jul 31, 2003
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alex Hunsley
    Replies:
    6
    Views:
    395
    Alex Martelli
    Oct 31, 2005
  2. Ed Leafe

    Mixin class error

    Ed Leafe, Mar 6, 2006, in forum: Python
    Replies:
    3
    Views:
    337
    Kent Johnson
    Mar 7, 2006
  3. Scott David Daniels

    Pending: A Mixin class for testing

    Scott David Daniels, Nov 26, 2006, in forum: Python
    Replies:
    1
    Views:
    323
    Peter Otten
    Nov 27, 2006
  4. Replies:
    2
    Views:
    319
    Nate Barney
    Sep 13, 2006
  5. John Lane
    Replies:
    6
    Views:
    210
    John Lane
    Feb 9, 2010
Loading...

Share This Page