run time linked attributes

Discussion in 'Python' started by michael.murr@gmail.com, May 28, 2006.

  1. Guest

    I've read a few posts about how to have attributes that are "linked" at
    run time. I've created a (simple) Python metaclass that accomplishes
    this with some behind-the-scenes __init__ redirection. I'm posting the
    code at the end in case anyone is interested.

    Problem background:
    Object a (an instance of class A) has an attribute that points to
    object b (which is an instance of class B). So A's __init__ might look
    something like this:
    __init__(self):
    self.b = B(arg1, arg2, arg3)

    The catch is, that instances of B() need to reference other attributes
    of A. The traditional way to do this is pass the instance of A as a
    parameter to B. So B's __init__ might look something like:
    __init__(self, creator, arg1, arg2, arg3):
    self.creator = creator;

    naturally, A's __init__ would now look something like:
    __init__(self):
    self.b = B(self, arg1, arg2, arg3)

    Essentially this creates two links:
    a = A();
    a.b --> b
    a.b.creator -> a

    To hide the passing of the reference to the parent/creator, the
    metaclass below adds a method MakeLinkedAttribute.

    To hide the handling of the reference to the parent/creator, the
    metaclass below redirects B's __init__ when the class object is
    created, inserting a call to Meta__init__, which handles the processing
    of the parent/creator element. The original __init__ is then called.
    See the module's docstring for an example...

    I'm curious to hear feedback about the code, especially any dangers
    that can occur from redirecting/hijacking __init__.

    Cheers!

    LinkedAttribute.py:
    """ Metaclass for making linked attributes

    The LinkedAttribute class allows you to (at run time) have objects
    that have references back to the object that created them.

    Any class that has LinkedAttribute as it's metaclass will have a
    MakedLinkedAttribute() method to make linked attributes.

    To accomplish this hackery, we use the metaclass to hijack the
    __init__
    method, replacing it with our own. The new __init__ method (defined
    as
    Meta__init__) sets up the _creator attribute (if it was passed in) and
    then
    calls the original __init__ function. The original __init__ function
    gets
    renamed to <class name>_old__init__. The reason for including the
    class name
    in the first part of the redefinition is so that sub classes that call
    super(...).__init__ won't enter an infinite loop.


    The restriction to using this metaclass is that the classes that you
    call
    MakeLinkedAttribute on must also have LinkedAttribute as a metaclass.

    If you use this metaclass, make sure to give credit where credit is
    due :)
    (e.g. in a comment or docstring)

    There are other ways of solving the same problem (including passing
    the
    parent to __init__ explicitly).


    The software is provided AS IS, use this software at your own risk.
    There
    is no warranty. By using this software you agree to hold the
    author(s)
    harmless of any damage whether direct, incidental, consequently and
    otherwise. In no event shall the author(s) of this code be liable for
    any
    damages whatsoever incurred by this code.

    (c) 2006 Michael Murr [mmurr at code-x d0t net]


    e.g.:
    -----

    from LinkedAttribute import LinkedAttribute

    class a(object):
    def __init__(self):
    self.linked_b = self.MakeLinkedAttribute(b, "this is a linked b")
    self.plain_b = b("this is a plain b")

    __metaclass__ = LinkedAttribute

    class b(object):
    def __init__(self, text):
    self.text = text
    if hasattr(self, "_creator"):
    print "I have a creator!"
    else:
    print "I am a standalone!"

    __metaclass__ = LinkedAttribute

    if __name__ == "__main__":
    objectA = a()
    objectB = b("created directly")

    print objectA.linked_b.text
    print objectA.plain_b.text
    print objectB.text



    yields:
    -------

    I have a creator!
    I am a standalone!
    I am a standalone!
    this is a linked b
    this is a plain b
    created directly

    """

    class LinkedAttribute(type):
    def __new__(klass, klassName, klassBases, klassDict):
    # Method to make a new linked child
    def MakeLinkedAttribute(self, childClass, *args, **kwds):
    return(childClass(_creator=self, *args, **kwds))
    # MakeLinkedAttribute(self, childClass, *args, **kwds):

    # Run time hijacking of __init__ so we can make
    # a _creator BEFORE the original __init__ is called
    #
    # We use klassName + "_hijacked__init__" so sub classes
    # who call super(...).__init__ won't enter infinite
    # loops
    #
    # Note: All your __init__ are belong to us :)
    def Meta__init__(self, *args, **kwds):
    # If we don't have _creator keyword do nothing
    if kwds.has_key("_creator"):
    self._creator = kwds["_creator"]
    del kwds["_creator"]
    # kwds.has_key("_creator"):

    # If we don't have an old init, do nothing
    if hasattr(self, klassName + "_hijacked__init__"):
    attr = getattr(self, klassName + "_hijacked__init__")
    attr(*args, **kwds)
    # hasattr(self, klassName + "_hijacked__init__"):
    # Meta__init__(self, *args, **kwds):

    # If we have an init, we need to save it
    if klassDict.has_key("__init__"): klassDict[klassName +
    "_hijacked__init__"] = klassDict["__init__"]

    # Hijack (redirect) __init__ for our [evil] purposes :)
    klassDict["__init__"] = Meta__init__
    instance = super(LinkedAttribute, klass).__new__(klass, klassName,
    klassBases, klassDict)
    instance.MakeLinkedAttribute = MakeLinkedAttribute

    return(instance)
    # __new__(klass, klassName, klassBases, klassDict):
    # LinkedAttribute(type):
    , May 28, 2006
    #1
    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. Chris Ritchey
    Replies:
    7
    Views:
    463
    emerth
    Jul 10, 2003
  2. Chris Ritchey

    Generating a char* from a linked list of linked lists

    Chris Ritchey, Jul 9, 2003, in forum: C Programming
    Replies:
    7
    Views:
    453
    emerth
    Jul 10, 2003
  3. Matthew Wilson
    Replies:
    6
    Views:
    290
    Nick Vatamaniuc
    Jul 20, 2006
  4. flamesrock
    Replies:
    8
    Views:
    434
    Hendrik van Rooyen
    Nov 24, 2006
  5. Pierre Yves
    Replies:
    2
    Views:
    470
    Pierre Yves
    Jan 10, 2008
Loading...

Share This Page