Handling Property and internal ('__') attribute inheritance andcreation

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Rafe

    Handling Property and internal ('__') attribute inheritance andcreation

    Hi,

    I've been thinking in circles about these aspects of Pythonic design
    and I'm curious what everyone else is doing and thinks. There are 3
    issues here:


    1) 'Declaring' attributes - I always felt it was good code practice to
    declare attributes in a section of the class namespace. I set anything
    that is constant but anything variable is set again in __init__():

    Class A(object):
    name = "a name"
    type = "a typee"
    childobject = None

    def __init__(self, obj):
    self.childobjec t = object

    This makes it easy to remember and figure out what is in the class.
    Granted there is nothing to enforce this, but that is why I called it
    'code practice'. Do you agree or is this just extra work?


    2) Internal attributes (starting with 2x'_') aren't inherited. Do you
    just switch to a single '_' when you want an "internal" attribute
    inherited? These are attributes I want the classes to use but not the
    user of these classes. Of course, like anything else in Python, these
    aren't really private. It is just a convention, right? (The example
    for #3 shows this.)


    3) It isn't possible to override a piece of a Property Descriptor. To
    get around this, I define the necessary functions in the class but I
    define the descriptor in the __new__() method so the inherting class
    can override the methods. Am I overlooking some basic design principle
    here? This seems like a lot of work for a simple behavior. Example:

    class Base(object):
    def __new__(cls):
    setattr(cls,
    "state",
    property(fget = cls._Get_state,
    fset = cls._Set_state,
    fdel = None,
    doc = cls._doc_state) )

    obj = super(Base, cls).__new__(cl s)
    return obj

    state = None # Set in __new__()
    _state = True
    _doc_state = "The state of this object"
    def _Get_state(self ): return self._state
    def _Set_state(self , value): self._state = value

    class Child(Base):
    def _Get_state(self ):
    # Do some work before getting the state.
    print "Getting the state using the child's method"
    return self._state

    print Child().state



    Please share your thoughts,

    - Rafe
  • Christian Heimes

    #2
    Re: Handling Property and internal ('__') attribute inheritance andcreation

    Bruno Desthuilliers wrote:
    How often do you really need to override a property ? (hint : as far as
    I'm concerned, it never happened so far). Now you have two solutions :
    either redefine the whole property in the derived class, or, if you
    really intend your property to be overriden, provide a "template method"
    hook.
    In Python 2.6 and 3.0 you can override the setter, getter or deleter of
    a property in a subclass. You may be able to find a pure Python
    implementation written by Guido. My C implementation in the core works
    almost the same.

    Christian

    Comment

    • Eric Brunel

      #3
      Re: Handling Property and internal ('__') attribute inheritance and creation

      On Fri, 15 Aug 2008 20:02:36 +0200, Rafe <rafesacks@gmai l.comwrote:
      [snip]
      1) 'Declaring' attributes - I always felt it was good code practice to
      declare attributes in a section of the class namespace. I set anything
      that is constant but anything variable is set again in __init__():
      >
      Class A(object):
      name = "a name"
      type = "a typee"
      childobject = None
      >
      def __init__(self, obj):
      self.childobjec t = object
      >
      This makes it easy to remember and figure out what is in the class.
      Granted there is nothing to enforce this, but that is why I called it
      'code practice'. Do you agree or is this just extra work?
      To add to what others have already said, it is not only 'just extra work',
      it is also quite dangerous. See:

      class A(object):
      children = []

      Now *all* A instances share the *same* list, as it was defined as a class
      attribute. If you ever forget to set it to something else in __init__,
      you're in for big surprises.

      What I'm doing is set all instance attributes right at the beginning of
      the __init__ with a huge comment before them, like:

      class A(object):
      def __init__(self):
      ## INSTANCE ATTRIBUTES:
      ## --------------------
      self.children = []

      This way, you still can 'figure out what is in the class' quite quickly,
      without the drawbacks of declaraing class attributes.

      HTH
      --
      python -c "print ''.join([chr(154 - ord(c)) for c in
      'U(17zX(%,5.zmz 5(17l8(%,5.Z*(9 3-965$l7+-'])"

      Comment

      • Fredrik Lundh

        #4
        Re: Handling Property and internal ('__') attribute inheritance andcreation

        Eric Brunel wrote:
        To add to what others have already said, it is not only 'just extra
        work', it is also quite dangerous. See:
        >
        class A(object):
        children = []
        the OP is aware of that, of course:
        I set anything that is constant but anything variable is set again in
        __init__()
        as long as if you're aware of the issues involved (which you should be
        if you're using Python professionally) , using class-level attributes is
        a perfectly valid Python style.

        </F>

        Comment

        • Bruno Desthuilliers

          #5
          Re: Handling Property and internal ('__') attribute inheritance andcreation

          Fredrik Lundh a écrit :
          Eric Brunel wrote:
          >
          >To add to what others have already said, it is not only 'just extra
          >work', it is also quite dangerous. See:
          >>
          >class A(object):
          > children = []
          >
          the OP is aware of that, of course:
          >
          I set anything that is constant but anything variable is set again in
          __init__()
          >
          as long as if you're aware of the issues involved (which you should be
          if you're using Python professionally) , using class-level attributes is
          a perfectly valid Python style.
          Using class attributes is perfectly valid Python style, indeed. But in
          this case - ie: using class attributes as a pseudo-declaration of
          instance attributes -, I would not call this good style : it's a waste
          of time, a violation of DRY, and a potential source of confusion for the
          class's users / maintainers.

          Comment

          • Rafe

            #6
            Re: Handling Property and internal ('__') attribute inheritance andcreation

            On Aug 16, 1:22 am, Bruno Desthuilliers
            <bdesth.quelque ch...@free.quel quepart.frwrote :
            Rafea écrit :
            >
            Hi,
            >
            I've been thinking in circles about these aspects of Pythonic design
            and I'm curious what everyone else is doing and thinks. There are 3
            issues here:
            >
            1) 'Declaring' attributes
            >
            There's nothing like "declaratio n" of variables/attributes/whatever in
            Python.
            >
            - I always felt it was good code practice to
            declare attributes in a section of the class namespace. I set anything
            that is constant but anything variable is set again in __init__():
            >
            Class A(object):
            name = "a name"
            type = "a typee"
            childobject = None
            >
            def __init__(self, obj):
            self.childobjec t = object
            >
            This makes it easy to remember and figure out what is in the class.
            Granted there is nothing to enforce this, but that is why I called it
            'code practice'. Do you agree or is this just extra work?
            >
            It's not only extra work, it's mostly a WTF. You create class attributes
            for no other reasons than to mimic some other mainstream languages. If I
            was to maintain such code, I'd loose valuable time wondering where these
            class attributes are used.
            >
            >
            >
            2) Internal attributes (starting with 2x'_') aren't inherited.
            >
            Yes they are. But you need to manually mangle them when trying to access
            them from a child class method. FWIW, that *is* the point of
            __name_mangling : making sure these attributes won't be accidentally
            overwritten in a child class.
            >
            Do you
            just switch to a single '_' when you want an "internal" attribute
            inherited? These are attributes I want the classes to use but not the
            user of these classes. Of course, like anything else in Python, these
            aren't really private. It is just a convention, right? (The example
            for #3 shows this.)
            >
            Yes. The (*very* strong) convention is that
            _names_with_sim ple_leading_und erscore denote implementation attributes.
            >
            >
            >
            3) It isn't possible to override a piece of a Property Descriptor. To
            get around this, I define the necessary functions in the class but I
            define the descriptor in the __new__() method so the inherting class
            can override the methods. Am I overlooking some basic design principle
            here? This seems like a lot of work for a simple behavior. Example:
            >
            class Base(object):
            def __new__(cls):
            setattr(cls,
            "state",
            property(fget = cls._Get_state,
            fset = cls._Set_state,
            fdel = None,
            doc = cls._doc_state) )
            >
            obj = super(Base, cls).__new__(cl s)
            return obj
            >
            state = None # Set in __new__()
            _state = True
            _doc_state = "The state of this object"
            def _Get_state(self ): return self._state
            def _Set_state(self , value): self._state = value
            >
            pep08 : attribute names (including methods) should be all_lower.
            >
            class Child(Base):
            def _Get_state(self ):
            # Do some work before getting the state.
            print "Getting the state using the child's method"
            return self._state
            >
            print Child().state
            >
            How often do you really need to override a property ? (hint : as far as
            I'm concerned, it never happened so far). Now you have two solutions :
            either redefine the whole property in the derived class, or, if you
            really intend your property to be overriden, provide a "template method"
            hook.
            >
            I'd say you're making things much more complicated than they need to be.

            Thanks Bruno, and everyone ! These are exactly the type of hard
            answers I was hoping for. I'm mostly converted but my brain still
            needs a Pythonic push from time to time. Looks like have some some
            clean up to perform...with confidence.

            I'm interested to see the implementation of getter, etc overrides in
            2.6/3.0. I have two classes that could be simplified with this. For
            example, I have a class which does a lot of work and has about 5 key
            properties. I want to inherit it, and just trigger an event (update
            something only stored in the child) after 4 of these attributes are
            finished being set. I was thinking about using a callback which is
            empty in the parent or __setattr__() (but I hat using this unless I
            have to, it is still troublesome to me).

            - Rafe


            Comment

            Working...