Best way to do attribute docstrings?

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

    Best way to do attribute docstrings?


    What's the best method for annotating attributes with a docstring?
    I'm looking to be able to introspect my class & get the comments back
    out.

    The technique I'm using is a little hoaky, but works.. basically I
    create subclasses of the builtin types that I want to be able to use &
    then instantiate them in my attribute assignments. This gives me an
    object that I can tweak the __doc__ attribute on. An example of what
    my code looks like is included below.

    I saw that PEP 224 [1] was trying to meet this need, but got rejected
    because the proposed syntax wasn't clear enough.

    Thanks!
    -Ken

    [1] http://www.python.org/dev/peps/pep-0224/


    attr_doc.py::

    # Subclass str so we can modify instance's attributes (like __doc__)
    class _(str): pass

    # Boolean gave me extra fits that I don't understand, but this
    technique works
    class MyBool(int):
    def __str__(self):
    return `self.__int__() 0`
    def __repr__(self):
    return self.__str__()

    def bool_func(val):
    def blah():
    return MyBool(val)
    return blah
    true = bool_func(True)
    false = bool_func(False )


    class Animal(object):
    four_legs = true()
    four_legs.__doc __ = "Animal has four legs"

    favorite_food = _('cheese')
    favorite_food._ _doc__ = "Animal's favorite food"

    has_fur = true()
    has_fur.__doc__ = "Animal has fur"

    print Animal.four_leg s.__doc__, '::', Animal.four_leg s
    print Animal.favorite _food.__doc__, '::', Animal.favorite _food
    print Animal.has_fur. __doc__, '::', Animal.has_fur

    ------
    This gives the expected results:

    Animal has four legs :: True
    Animal's favorite food :: cheese
    Animal has fur :: True

  • Gabriel Genellina

    #2
    Re: Best way to do attribute docstrings?

    En Fri, 07 Sep 2007 17:06:07 -0300, Ken Kuhlman <kskuhlman@gmai l.com>
    escribi�:
    What's the best method for annotating attributes with a docstring?
    I'm looking to be able to introspect my class & get the comments back
    out.
    I don't know which is the *best* method. Perhaps you might use properties
    instead. Or some kind of convention, like
    four_legs__doc_ _ = "Animal has four legs"
    to be the docstring associate to `four_legs` attribute.
    The technique I'm using is a little hoaky, but works.. basically I
    create subclasses of the builtin types that I want to be able to use &
    then instantiate them in my attribute assignments. This gives me an
    object that I can tweak the __doc__ attribute on. An example of what
    my code looks like is included below.
    I don't like subclassing builtins, it doesn't work in general. _("Hello")
    + _(" world!") is a plain str object, not your derived class.
    What about instance attributes? All your examples show class attributes.
    Your docstring appears to be attached to the attribute "value", but it
    should be attached to the attribute definition, or be a class attribute,
    or something like that, shared between all instances and somewhat
    permanent. Else, reassigning the attribute will lose the docstring.
    # Boolean gave me extra fits that I don't understand, but this
    technique works
    class MyBool(int):
    def __str__(self):
    return `self.__int__() 0`
    def __repr__(self):
    return self.__str__()
    Let Python do the boolean conversion: -1 is a true value, but MyBool(-1)
    would say False.
    I don't understand exactly why do you want this class, but I'd write it
    this way:

    class MyBool(int):
    def __str__(self):
    return str(bool(self))
    __repr__ = __str__
    def bool_func(val):
    def blah():
    return MyBool(val)
    return blah
    true = bool_func(True)
    false = bool_func(False )
    And why do you need such functions?

    --
    Gabriel Genellina

    Comment

    • Ken Kuhlman

      #3
      Re: Best way to do attribute docstrings?


      Thanks for the response! It was just the kick I needed to realize
      that I was letting my frustration get the best of me and that I was
      going down a dead-end. I blame the fact that I was coding on little
      sleep :-)

      I went with the solution of giving a naming convention to the
      docstrings and relying on that for the introspection -- that's a lot
      less of a kludge than what I was attempting.

      I still think it would be great if you could do something like:
      @doc('Animal has four legs')
      four_legs = True

      IMHO, that syntax is nice (which was the objection to PEP 224), but
      I'm not going to try to propose another PEP over it. My itch is
      scratched for now -- if the naming convention hack gets under my skin
      eventually I'll try going down a source parsing route next.

      Thanks again for the help!
      -Ken

      PS: I hope it's OK that I ignored your questions -- my initial
      solution was just too hideous to be scrutinized too closely.

      Comment

      • Ken Kuhlman

        #4
        Re: Best way to do attribute docstrings?

        Replying to myself in case someone finds this interesting.

        Anyway, I took another shot at this with a little fresher mind, and it
        was quickly obvious that I was trying to force attributes to behave
        more like classes. It was a small step from there to creating a
        factory function to return instances of the appropriate class. I'm
        much happier with the result than either of the two previously posted
        kludges.


        # A factory function for generating attributes that can be annotated.
        def attr(value, doc=None):
        base = type(value)
        if base == bool:
        # bool class can't be used as a base, so we make one that can.
        class MyBool(int):
        def __str__(self):
        return str(bool(self))
        __repr__ = __str__
        base = MyBool

        class FancyAttr(base) :
        pass

        fa = FancyAttr(value )
        fa.__doc__ = doc
        return fa


        class Animal(object):
        four_legs = attr(value = True, doc = "Animal has four legs")
        favorite_food = attr('cheese', doc = "Animal's favorite food")
        has_fur = attr(False)
        has_fur.__doc__ "Animal has fur"

        print Animal.four_leg s.__doc__, '::', Animal.four_leg s
        print Animal.favorite _food.__doc__, '::', Animal.favorite _food
        print Animal.has_fur. __doc__, '::', Animal.has_fur


        Comment

        • Gabriel Genellina

          #5
          Re: Best way to do attribute docstrings?

          En Tue, 25 Sep 2007 22:41:31 -0300, Ken Kuhlman <kskuhlman@gmai l.com>
          escribi�:
          Replying to myself in case someone finds this interesting.
          >
          Anyway, I took another shot at this with a little fresher mind, and it
          was quickly obvious that I was trying to force attributes to behave
          more like classes. It was a small step from there to creating a
          factory function to return instances of the appropriate class. I'm
          much happier with the result than either of the two previously posted
          kludges.
          Still there is something I don't understand on your design. You appear to
          be always concerned about *class* attributes. *Instance* attributes are
          far more comon, and usually they change their value many times.
          class Animal(object):
          four_legs = attr(value = True, doc = "Animal has four legs")
          favorite_food = attr('cheese', doc = "Animal's favorite food")
          has_fur = attr(False)
          has_fur.__doc__ "Animal has fur"
          As an example, how would you annotate attributes on a hierarchy like this?

          class Animal(object):
          can_fly = False # no Animal can fly unless explicitely noted
          lives = 1 # most Animals have a single life
          def __init__(self, color, legs, favorite_food):
          self.color = color
          self.legs = legs
          self.favorite_f ood = favorite_food

          class Mammal(Animal):
          pass

          class Cat(Mammal):
          def __init__(self, color):
          Mammal.__init__ (self, color=color, legs=4, favorite_food=' mice')
          self.lives = 7 # a cat starts with 7 lives

          class Mouse(Mammal):
          def __init__(self, color, personality):
          Mammal.__init__ (self, color=color, legs=4, favorite_food=' cheese')
          self.personalit y = personality

          class Bird(Animal):
          can_fly = True
          def __init__(self, color):
          Animal.__init__ (self, color=color, legs=2, favorite_food=' seed')

          tweety = Bird('yellow')
          sylvester = Cat('black')
          tom = Cat('blue')
          jerry = Mouse('brown', 'nice')
          itchy = Mouse('blue', 'sadist')
          scratchy = Cat('black')
          scratchy.lives = 7**7 # or so...

          print tweety.legs
          print scratchy.color
          print scratchy.lives

          --
          Gabriel Genellina

          Comment

          • Ken Kuhlman

            #6
            Re: Best way to do attribute docstrings?

            On Sep 26, 12:25 am, "Gabriel Genellina" <gagsl-...@yahoo.com.a r>
            wrote:
            En Tue, 25 Sep 2007 22:41:31 -0300,KenKuhlman <kskuhl...@gmai l.com>
            escribi?:
            >
            Replying to myself in case someone finds this interesting.
            >
            Anyway, I took another shot at this with a little fresher mind, and it
            was quickly obvious that I was trying to force attributes to behave
            more like classes. It was a small step from there to creating a
            factory function to return instances of the appropriate class. I'm
            much happier with the result than either of the two previously posted
            kludges.
            >
            Still there is something I don't understand on your design. You appear to
            be always concerned about *class* attributes. *Instance* attributes are
            far more comon, and usually they change their value many times.
            >
            ....
            Gabriel Genellina

            I've only cared about class attributes to this point because my needs
            have been simple. They may not always be, however, so I'll take a
            shot at your challenge (below). I've basically just added a base
            class that defines __setattr__ to the mix.

            Thanks for the replies!
            -Ken


            # A factory function for generating attributes that can be annotated.
            def attr(value, doc=None):
            base = type(value)
            if base == bool:
            # bool class can't be used as a base, so we make one that can.
            class MyBool(int):
            def __str__(self):
            return str(bool(self))
            __repr__ = __str__
            base = MyBool

            class FancyAttr(base) :
            pass

            fa = FancyAttr(value )
            fa.__doc__ = doc
            return fa

            class AnnotatedAttrsB ase(object):
            _sticky_docs = True #False
            def __setattr__(sel f, name, value):
            """ Make sure attributes are fancy, maintaining docs if
            they're sticky. """
            if type(value).__n ame__ != 'FancyAttr':
            doc = None
            if self._sticky_do cs and hasattr(self, name):
            doc = self.__dict__[name].__doc__
            self.__dict__[name] = attr(value, doc)
            else:
            self.__dict__[name] = value

            class Animal(Annotate dAttrsBase):
            can_fly = attr(value = False,
            doc = "no Animal can fly unless explicitly noted")
            lives = attr(value = 1,
            doc = "most Animals have a single life")
            def __init__(self, color, legs, favorite_food):
            self.color = attr(color, "every animal has a color")
            self.legs = attr(legs, "most animals have legs")
            self.favorite_f ood = favorite_food

            class Mammal(Animal):
            pass

            class Cat(Mammal):
            def __init__(self, color):
            Mammal.__init__ (self, color=color, legs=4,
            favorite_food=' mice')
            self.lives = attr(value = 7,
            doc = "a cat starts with 7 lives")

            class Mouse(Mammal):
            def __init__(self, color, personality):
            Mammal.__init__ (self, color=color, legs=4,
            favorite_food=' cheese')
            self.personalit y = personality

            class Bird(Animal):
            can_fly = True
            _sticky_docs = False
            def __init__(self, color):
            Animal.__init__ (self, color=color, legs=2,
            favorite_food=' seed')

            tweety = Bird('yellow')
            tweety.lives = 42
            sylvester = Cat('black')
            tom = Cat('blue')
            jerry = Mouse('brown', 'nice')
            itchy = Mouse('blue', 'sadist')
            scratchy = Cat('black')
            scratchy.lives = attr(7**7, "or so...")

            print scratchy.color, scratchy.color. __doc__
            print scratchy.lives, scratchy.lives. __doc__
            print tweety.legs, tweety.legs.__d oc__
            print tweety.lives, tweety.lives.__ doc__

            Comment

            Working...