Deciding inheritance at instantiation?

Discussion in 'Python' started by Tobiah, Aug 3, 2012.

  1. Tobiah

    Tobiah Guest

    I have a bunch of classes from another library (the html helpers
    from web2py). There are certain methods that I'd like to add to
    every one of them. So I'd like to put those methods in a class,
    and pass the parent at the time of instantiation. Web2py has
    a FORM class for instance. I'd like to go:

    my_element = html_factory(FORM)

    Then my_element would be an instance of my class, and also
    a child of FORM.

    I started messing with decorators, but it became difficult
    for me to visualise how to do this.

    Thanks!

    Toby
    Tobiah, Aug 3, 2012
    #1
    1. Advertising

  2. Tobiah

    Terry Reedy Guest

    On 8/3/2012 4:48 PM, Tobiah wrote:
    > I have a bunch of classes from another library (the html helpers
    > from web2py). There are certain methods that I'd like to add to
    > every one of them. So I'd like to put those methods in a class,
    > and pass the parent at the time of instantiation. Web2py has
    > a FORM class for instance. I'd like to go:
    >
    > my_element = html_factory(FORM)
    >
    > Then my_element would be an instance of my class, and also
    > a child of FORM.
    >
    > I started messing with decorators, but it became difficult
    > for me to visualise how to do this.


    Use type(name, bases, content) for dynamic class creation.

    --
    Terry Jan Reedy
    Terry Reedy, Aug 3, 2012
    #2
    1. Advertising

  3. Tobiah

    Nobody Guest

    On Fri, 03 Aug 2012 13:48:08 -0700, Tobiah wrote:

    > I have a bunch of classes from another library (the html helpers
    > from web2py). There are certain methods that I'd like to add to
    > every one of them. So I'd like to put those methods in a class,
    > and pass the parent at the time of instantiation. Web2py has
    > a FORM class for instance. I'd like to go:
    >
    > my_element = html_factory(FORM)
    >
    > Then my_element would be an instance of my class, and also
    > a child of FORM.


    You can use type() to create classes dynamically. E.g.:

    class my_base_class(object):
    # extra methods

    subclasses = {}

    def html_factory(cls, *args, **kwargs):
    name = "my_" + cls.__name__
    if name not in subclasses:
    subclasses[name] = type(name, (cls, my_base_class), {})
    return subclasses[name](*args, **kwargs)
    Nobody, Aug 4, 2012
    #3
  4. On Fri, 03 Aug 2012 13:48:08 -0700, Tobiah wrote:

    > I have a bunch of classes from another library (the html helpers from
    > web2py). There are certain methods that I'd like to add to every one of
    > them. So I'd like to put those methods in a class, and pass the parent
    > at the time of instantiation. Web2py has a FORM class for instance.
    > I'd like to go:
    >
    > my_element = html_factory(FORM)
    >
    > Then my_element would be an instance of my class, and also a child of
    > FORM.


    I cannot understand what you are actually trying to do here because you
    aren't giving enough information and the description you give is
    misleading. But from what little I can grasp, I think it sounds like an
    unclean, confusing design and you would be better off with either mixins,
    composition, or code injection.

    What is html_factory? By the name, it should return some HTML. But you're
    assigning the output to something called "my_element", which suggests it
    is returning only a single element of HTML. To me, I would expect that to
    be a string. Consequently, it isn't clear to me what you actually want,
    and I'm forced to make some wild guesses, and I can see a number of
    different alternative approaches.


    === Mixins ===

    You state:

    There are certain methods that I'd like to add to every
    one of [my classes]. So I'd like to put those methods
    in a class, and pass the parent at the time of instantiation

    Don't pass the utility class at instantiation time. Use it as a mixin
    class.

    class UtilityMixin:
    # add "those methods" to this class
    pass


    class MyClassA(MyParentClass, UtilityMixin):
    pass

    class MyClassB(AnotherClass, UtilityMixin):
    pass

    class MyClassC(MyClassB): # already inherits from UtilityMixin
    pass


    === Composition ===


    This frankly sounds like an abuse of inheritance. Inheritance is for
    modelling "is-a" relationships, not just for sticking arbitrary lumps of
    unrelated code together. If I can understand what you are trying to do,
    then you need to model a "has-a" relationship. For example:

    The Contact Us page is not a html form, it HAS a html form;

    therefore the instance which creates the Contact Us page is not a html
    form either, and should not inherit from FormClass;

    but it should have a FormClass instance it can delegate the creation of
    the form to.


    Something like this, perhaps:

    contact_page_designer = PageDesigner()
    contact_page_designer.form_designer = FormClass()


    This can be wrapped inside the __init__ method, of course. The FormClass
    instance can be passed as a generic argument.

    Then, your PageDesigner methods which need to create a form simply
    delegate the work to the form_designer attribute. Instead of this:

    self.make_form()

    which depends on self having ten different methods to do with making
    forms, you do this:

    self.form_designer.make_form()

    and all the form-related methods are encapsulated in one place, out of
    the way. This general technique is known as composition, or delegation,
    and you use it every time you do something like this:

    result = self.name.upper() # delegating upper method to the string name

    And yet, somehow people forget it in favour of inheritance once they move
    beyond the primitive built-in types.


    === Code injection ===

    You talk about deciding inheritance at instantiation time, which implies
    that each instance will get different methods. If so, then so long as you
    aren't changing dunder methods (double leading and trailing underscore
    special methods like __init__ and friends), you can inject methods
    directly onto an instance, either to add new functionality or override
    existing functionality on a per-instance basis.


    py> class Parrot:
    .... def speak(self):
    .... print "Polly wants a cracker!"
    ....
    py> class KillBot:
    .... def speak(self):
    .... print "Crush! Kill! Destroy!"
    ....
    py> p = Parrot()
    py> p.speak()
    Polly wants a cracker!
    py> p.speak = KillBot().speak
    py> p.speak()
    Crush! Kill! Destroy!


    === Dynamic class creation ===

    Forget about using type(), there's an easier way.


    def factory(name, parent_class):
    class MyClass(parent_class):
    def method(self):
    print "Called method"
    return 42
    MyClass.__name__ = name
    return MyClass


    Much easier than the equivalent using type.


    def method(self):
    print "Called method"
    return 42

    type(name, (parent_class,), {'method': method})



    --
    Steven
    Steven D'Aprano, Aug 4, 2012
    #4
  5. On 8/3/2012 4:48 PM, Tobiah wrote:
    > I have a bunch of classes from another library (the html helpers
    > from web2py). There are certain methods that I'd like to add to
    > every one of them. So I'd like to put those methods in a class,
    > and pass the parent at the time of instantiation. Web2py has
    > a FORM class for instance. I'd like to go:
    >
    > my_element = html_factory(FORM)
    >
    > Then my_element would be an instance of my class, and also
    > a child of FORM.
    >
    > I started messing with decorators, but it became difficult
    > for me to visualise how to do this.
    >
    > Thanks!
    >
    > Toby


    Your class inherits from whatever is in the class statement.

    class Foo(object):
    pass

    Here, Foo inherits from object, but you can replace object with any tuple of
    classes which can be redefined before instantiation.

    class Base1(object):
    pass

    class Base2(object):
    pass

    Now we can define Foo2 to inherit from something that better be a tuple of
    classes at instantiation time.

    class Foo2(bases):
    pass

    bases = (Base1,)

    foo2 = Foo2() # foo2 is a Foo2 which inherits from Base1.

    bases = (Base1, Bace2)

    foob1b2 = Foo2() # foob1b2 is a Foo2 which inherits from Base1 and Base2.

    Who was it who said: "Give a man a shovel and he'll dig himself one helluva hole"?

    --
    Time flies like the wind. Fruit flies like a banana. Stranger things have .0.
    happened but none stranger than this. Does your driver's license say Organ ..0
    Donor?Black holes are where God divided by zero. Listen to me! We are all- 000
    individuals! What if this weren't a hypothetical question?
    steveo at syslang.net
    Steven W. Orr, Aug 4, 2012
    #5
  6. Tobiah

    Tobiah Guest

    On 08/03/2012 02:55 PM, Terry Reedy wrote:
    > On 8/3/2012 4:48 PM, Tobiah wrote:
    >> I have a bunch of classes from another library (the html helpers
    >> from web2py). There are certain methods that I'd like to add to
    >> every one of them. So I'd like to put those methods in a class,
    >> and pass the parent at the time of instantiation. Web2py has
    >> a FORM class for instance. I'd like to go:
    >>
    >> my_element = html_factory(FORM)
    >>
    >> Then my_element would be an instance of my class, and also
    >> a child of FORM.
    >>
    >> I started messing with decorators, but it became difficult
    >> for me to visualise how to do this.

    >
    > Use type(name, bases, content) for dynamic class creation.
    >


    Very cool. Just what I was after. Thanks.

    Tobiah
    Tobiah, Aug 6, 2012
    #6
  7. Tobiah

    alex23 Guest

    On Aug 4, 6:48 am, Tobiah <> wrote:
    > I have a bunch of classes from another library (the html helpers
    > from web2py).  There are certain methods that I'd like to add to
    > every one of them.  So I'd like to put those methods in a class,
    > and pass the parent at the time of instantiation.  Web2py has
    > a FORM class for instance.  I'd like to go:
    >
    >         my_element = html_factory(FORM)
    >
    > Then my_element would be an instance of my class, and also
    > a child of FORM.


    I've lately begun to prefer composition over inheritance for
    situations like this:

    class MyElementFormAdapter(object):
    def __init__(self, form):
    self.form = form

    def render_form(self):
    self.form.render()

    my_element = MyElementFormAdapter(FORM)
    my_element.render_form()
    my_element.form.method_on_form()

    Advantages include being more simple and obvious than multiple
    inheritance, and avoiding namespace clashes:

    class A(object):
    def foo(self):
    print 'a'

    class B(object):
    def foo(self):
    print 'b'

    class InheritFromAB(A, B):
    pass

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

    >>> inherit = InheritFromAB()
    >>> inherit.foo()

    a
    >>> adapt = AdaptAB(A(), B())
    >>> adapt.a.foo()

    a
    >>> adapt.b.foo()

    b
    alex23, Aug 7, 2012
    #7
  8. Tobiah

    Tobiah Guest

    Interesting stuff. Thanks.

    On 08/06/2012 07:53 PM, alex23 wrote:
    > On Aug 4, 6:48 am, Tobiah<> wrote:
    >> I have a bunch of classes from another library (the html helpers
    >> from web2py). There are certain methods that I'd like to add to
    >> every one of them. So I'd like to put those methods in a class,
    >> and pass the parent at the time of instantiation. Web2py has
    >> a FORM class for instance. I'd like to go:
    >>
    >> my_element = html_factory(FORM)
    >>
    >> Then my_element would be an instance of my class, and also
    >> a child of FORM.

    >
    > I've lately begun to prefer composition over inheritance for
    > situations like this:
    >
    > class MyElementFormAdapter(object):
    > def __init__(self, form):
    > self.form = form
    >
    > def render_form(self):
    > self.form.render()
    >
    > my_element = MyElementFormAdapter(FORM)
    > my_element.render_form()
    > my_element.form.method_on_form()
    >
    > Advantages include being more simple and obvious than multiple
    > inheritance, and avoiding namespace clashes:
    >
    > class A(object):
    > def foo(self):
    > print 'a'
    >
    > class B(object):
    > def foo(self):
    > print 'b'
    >
    > class InheritFromAB(A, B):
    > pass
    >
    > class AdaptAB(object):
    > def __init__(self, a, b):
    > self.a = a
    > self.b = b
    >
    > >>> inherit = InheritFromAB()
    > >>> inherit.foo()

    > a
    > >>> adapt = AdaptAB(A(), B())
    > >>> adapt.a.foo()

    > a
    > >>> adapt.b.foo()

    > b
    Tobiah, Aug 7, 2012
    #8
    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. satya

    Deciding Data Access Strategy

    satya, Dec 9, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    305
    satya
    Dec 9, 2003
  2. stan k.
    Replies:
    1
    Views:
    538
  3. Jim
    Replies:
    1
    Views:
    245
    Gabriel Genellina
    Nov 16, 2006
  4. Achintya
    Replies:
    4
    Views:
    383
    Jim Langston
    Sep 7, 2005
  5. Replies:
    1
    Views:
    562
    Salt_Peter
    Dec 25, 2006
Loading...

Share This Page