FAQ
Greetings,


I'm hava a class in which there are two equally useful names for one
method. Consider this design (there are other approaches, but that's
not what my question is about):


class Spam1:


     def eggs(self):
         '''Return the Meaning of Life.'''
         return 42


     ham = eggs


help(Spam1) shows that ham = eggs(self), which isn't all bad, but it
could be better. help(Spam1.ham) shows the help for eggs; I know why,
but this could be better as well. And in any case, eggs looks somehow
better than ham, because eggs has its own def statement and ham doesn't.


Now consider this design, designed to overcome the previous issues:


class Spam2:


     def _private(self):
         '''Return the Meaning of Life.'''
         return 42


     ham = _private
     eggs = _private


Now help(Spam2.ham) and help(Spam2.eggs) show the same thing, but
help(Spam2) hides _private and its docstring and shows that ham and eggs
both call _private. That's no good. I can expose _private (e.g., by
renaming it to public), but that defeats the purpose of making it
private in the first place. I can go ahead and define ham to invoke
eggs, but then I have to duplicate the docstring, and it's not
being-hit-on-the-head obvious that ham and eggs are simply synonyms for
the same functionality.


I could put the documentation at the class level, but then it doesn't
show up as part of help(Spam2.eggs) or help(Spam1.ham).


So is there a clean way to define SpamN such that help(SpamN),
help(SpamN.ham), and help(SpamN.eggs) all do the Right Thing, and the
symmetry of ham and eggs is perfectly obvious to the most casual
observer?


Thanks,
Dan

Search Discussions

  • Steven D'Aprano at Aug 22, 2013 at 6:39 am

    On Thu, 22 Aug 2013 05:13:03 +0000, Dan Sommers wrote:


    Greetings,

    I'm hava a class in which there are two equally useful names for one
    method. Consider this design (there are other approaches, but that's
    not what my question is about):

    Generally though, one name will be the canonical or preferred name, and
    the other merely an alias. That being the case, it's reasonable for the
    alias to be "second class" in some fashion, as you show below.



    class Spam1:

    def eggs(self):
    '''Return the Meaning of Life.'''
    return 42

    ham = eggs

    help(Spam1) shows that ham = eggs(self), which isn't all bad, but it
    could be better. help(Spam1.ham) shows the help for eggs; I know why,
    but this could be better as well.

    I'm not entirely sure how it could possibly be better. Since ham is just
    another name for eggs, it makes sense that they show the same docstring.



    And in any case, eggs looks somehow
    better than ham, because eggs has its own def statement and ham doesn't.

    I don't think I agree, but perhaps that's just an aesthetic judgement
    where we disagree.


    [...]
    So is there a clean way to define SpamN such that help(SpamN),
    help(SpamN.ham), and help(SpamN.eggs) all do the Right Thing, and the
    symmetry of ham and eggs is perfectly obvious to the most casual
    observer?

    class Spam:
         def eggs(self):
             """eggs docstring"""
             return "ham and eggs"
         def ham(self):
             return self.eggs()
         ham.__doc__ = eggs.__doc__.replace('eggs', 'ham')


    This allows you two distinct docstrings, at the cost of duplicating the
    information in them. Spam.ham will be a *tiny* bit less efficient, due to
    the extra method call, but if you're worried about that, you're probably
    up to no good :-)


    But really, I would find that a confusing API. I would wonder what subtle
    difference in semantics there was between ham and eggs. I would much
    prefer to see that ham was just an alias:


    class Spam:
         def eggs(self):
             """eggs docstring"""
             pass
         ham = eggs




    which brings us back to the beginning of your post :-)


    --
    Steven
  • Dan Sommers at Aug 22, 2013 at 12:54 pm

    On Thu, 22 Aug 2013 06:39:48 +0000, Steven D'Aprano wrote:


    On Thu, 22 Aug 2013 05:13:03 +0000, Dan Sommers wrote:
    class Spam1:

    def eggs(self):
    '''Return the Meaning of Life.'''
    return 42

    ham = eggs


    help(Spam1) shows that ham = eggs(self), which isn't all bad, but it
    could be better. help(Spam1.ham) shows the help for eggs; I know
    why, but this could be better as well.
    I'm not entirely sure how it could possibly be better. Since ham is
    just another name for eggs, it makes sense that they show the same
    docstring.

    Yes, help(Spam1.eggs) and help(Spam1.ham) show the same docstring.
    help(Spam1), however, doesn't show any docstring for ham; it shows that
    ham = eggs(self).

    And in any case, eggs looks somehow better than ham, because eggs has
    its own def statement and ham doesn't.
    I don't think I agree, but perhaps that's just an aesthetic judgement
    where we disagree.

    Yep, just the aesthetics.

    class Spam:
    def eggs(self):
    """eggs docstring"""
    return "ham and eggs"
    def ham(self):
    return self.eggs()
    ham.__doc__ = eggs.__doc__.replace('eggs', 'ham')

    This allows you two distinct docstrings, at the cost of duplicating
    the information in them. Spam.ham will be a *tiny* bit less efficient,
    due to the extra method call, but if you're worried about that, you're
    probably up to no good :-)

    That I am up to no good goes without saying! ;-)

    But really, I would find that a confusing API. I would wonder what
    subtle difference in semantics there was between ham and eggs. I would
    much prefer to see that ham was just an alias:

    class Spam:
    def eggs(self):
    """eggs docstring"""
    pass
    ham = eggs

    which brings us back to the beginning of your post :-)

    Yeah, okay, I'll go with that, despite the asymmetry. The names in
    question are encrypt and decrypt, which for a stream cipher, are the
    same.


    Thanks, Steven, for confirming my ability to read the documentation and
    play around in my interactive shell. ;-)


    And Thanks, F?bio, for your suggestions, too.


    --
    Dan
  • Fábio Santos at Aug 22, 2013 at 9:10 am

    On 22 Aug 2013 06:17, "Dan Sommers" wrote:
    Greetings,

    I'm hava a class in which there are two equally useful names for one
    method. Consider this design (there are other approaches, but that's
    not what my question is about):

    class Spam1:

    def eggs(self):
    '''Return the Meaning of Life.'''
    return 42

    ham = eggs

    help(Spam1) shows that ham = eggs(self), which isn't all bad, but it
    could be better. help(Spam1.ham) shows the help for eggs; I know why,
    but this could be better as well. And in any case, eggs looks somehow
    better than ham, because eggs has its own def statement and ham doesn't.

    Now consider this design, designed to overcome the previous issues:

    class Spam2:

    def _private(self):
    '''Return the Meaning of Life.'''
    return 42

    ham = _private
    eggs = _private

    Now help(Spam2.ham) and help(Spam2.eggs) show the same thing, but
    help(Spam2) hides _private and its docstring and shows that ham and eggs
    both call _private. That's no good. I can expose _private (e.g., by
    renaming it to public), but that defeats the purpose of making it
    private in the first place. I can go ahead and define ham to invoke
    eggs, but then I have to duplicate the docstring, and it's not
    being-hit-on-the-head obvious that ham and eggs are simply synonyms for
    the same functionality.

    I could put the documentation at the class level, but then it doesn't
    show up as part of help(Spam2.eggs) or help(Spam1.ham).

    So is there a clean way to define SpamN such that help(SpamN),
    help(SpamN.ham), and help(SpamN.eggs) all do the Right Thing, and the
    symmetry of ham and eggs is perfectly obvious to the most casual
    observer?

    Thanks,
    Dan

    If if one of them is the canonical method name, you could define the other
    with a docstring indicating it is an alias for the other. If you don't want
    to spend code lines you can just define a helper function for that. Heck,
    you can even warn a DeprecationWarning if the alias is just backwards
    compatibility.
    -------------- next part --------------
    An HTML attachment was scrubbed...
    URL: <http://mail.python.org/pipermail/python-list/attachments/20130822/33be64c8/attachment-0001.html>

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedAug 22, '13 at 5:13a
activeAug 22, '13 at 12:54p
posts4
users3
websitepython.org

People

Translate

site design / logo © 2021 Grokbase