utility functions within a class?

Discussion in 'Python' started by John Salerno, May 8, 2006.

  1. John Salerno

    John Salerno Guest

    I might be missing something obvious here, but I decided to experiment
    with writing a program that involves a class, so I'm somewhat new to
    this in Python.

    Anyway, what is the best way to create a function (A) within a class
    that another function (B) can use? Function A is not something that an
    instance will ever call, so I figure it's a choice between static or
    class methods, but I don't know which one, or if this is even the right
    approach.

    Specifically, I am writing a class that defines methods that wrap string
    arguments inside HTML elements, and ultimately creates and HTML page. I
    know there are probably a ton of programs like this already, but this is
    just to give me something to do with Python.

    So I have a generate() method that will create the final HTML file once
    you are done creating elements. First it will create a string with the
    proper DTD, then it will append the <head> element and the <body>
    element, wrapped in the <html> element.

    Rather than have the generate() function do all the work, I thought I
    could write two utility functions to generate the head and body
    elements. These would simply wrap the element names around some
    pre-defined text (for the head) and around all the other elements (for
    the body).

    So I'm wondering, how would I define these two functions? They would be
    called from the generate method solely for the purpose of creating the
    head and body blocks.

    Thanks!
     
    John Salerno, May 8, 2006
    #1
    1. Advertising

  2. John Salerno

    Guest

    It sounds like all you want is some encapsulation, the following makes
    methods __head__ and __body__ "private" - the double underscores are
    important. I'd suggest reading the Object bits of the python tutorial
    also.

    class HTMLWrapper:

    def generate(self, ...):
    ...
    self.__head__(foo)
    ...
    self.__body__(bar)
    ...

    def __head__(self, ...):
    ...

    def __body__(self, ...):
    ...
     
    , May 8, 2006
    #2
    1. Advertising

  3. John Salerno

    Guest

    You do *NOT* want to put double-underscores before and after a method
    name. That does not indicate a private method, it indicates a "magic
    method" -- something that has special meaning to Python. Thus, you
    have special methods like __init__(), __len__(), __getattr__(),
    __setattr__(), etc; all of these methods may be called *by Python* in
    certain specific circumstances, and allow you to customize how your
    objects respond to those circumstances.

    Naming methods that are *not* special "magic methods" using this naming
    convention is a very bad idea.

    On the other hand, methods with only a single or double *leading*
    underscore, and no trailing underscore(s), can be considered to express
    some degree of privacy. A single underscore, by convention, indicates
    an internal method or attribute, and that name will typically not be
    exported. A double underscore will trigger minimal name mangling; not
    only will the name not be exported, but it will be converted to
    _<classname>__<name>, making it a bit more difficult to access from
    outside the class. (Access inside the class is via the unmangled
    name.)

    In this circumstance, I'd probably have methods _generate_head(self)
    and _generate_body(self). Don't mess with making them class/static
    methods unless it's important to be able to access them when you don't
    have any instance of the class available (and if you're calling them
    from inside a regular method, then you *do* have an instance
    available). Even if you don't end up referring to self or any instance
    attributes within the method, it's simpler to keep it as a normal
    method.

    --Jeff Shannon
     
    , May 8, 2006
    #3
  4. John Salerno

    Guest

    > You do *NOT* want to put double-underscores before and after a method
    > name. That does not indicate a private method, it indicates a "magic
    > method"


    WHOOPS!!

    Sorry, I haven't touched python for a few months and just started
    working on a script this morning so was going to post my own question
    when I got sidetracked answering this thread. I guess that might be a
    good reason not to use underscores as significant syntax.

    Cheers,
    -B
     
    , May 8, 2006
    #4
  5. John Salerno

    John Salerno Guest

    wrote:

    > Even if you don't end up referring to self or any instance
    > attributes within the method, it's simpler to keep it as a normal
    > method.


    Thanks, that makes sense to me! So basically just create them as
    methods, and if I want a little 'privacy' I can lead with an underscore?
    Somehow that sounds like the right idea... :)
     
    John Salerno, May 8, 2006
    #5
  6. John Salerno

    John Salerno Guest

    wrote:

    > Even if you don't end up referring to self or any instance
    > attributes within the method


    Hmm, follow-up: I *do* plan to refer to instance attributes inside these
    methods (self.something), but does that require that they be instance
    methods, or can they still reference 'self' since they are inside the class?

    They won't be called directly from an instance, which is why I wondered
    about making them static or class methods, but can static or class
    methods use self, or does it have to be an instance method in that case?
     
    John Salerno, May 8, 2006
    #6
  7. John Salerno

    John Salerno Guest

    John Salerno wrote:
    > wrote:
    >
    >> Even if you don't end up referring to self or any instance
    >> attributes within the method

    >
    > Hmm, follow-up: I *do* plan to refer to instance attributes inside these
    > methods (self.something), but does that require that they be instance
    > methods, or can they still reference 'self' since they are inside the class?
    >
    > They won't be called directly from an instance, which is why I wondered
    > about making them static or class methods, but can static or class
    > methods use self, or does it have to be an instance method in that case?


    Ugh, sorry about another post, but let me clarify: In these utility
    functions, I need to refer to an attribute of an instance, but these
    functions will be called from another method in the class, not from the
    instance itself. Is this even possible, or would 'self' have no meaning
    when used this way?
     
    John Salerno, May 8, 2006
    #7
  8. John Salerno

    Guest

    John Salerno wrote:
    > Ugh, sorry about another post, but let me clarify: In these utility
    > functions, I need to refer to an attribute of an instance, but these
    > functions will be called from another method in the class, not from the
    > instance itself. Is this even possible, or would 'self' have no meaning
    > when used this way?


    I'm having trouble deciphering what this bit means - "but these
    functions will be called from another method in the class, not from the
    instance itself", I don't think it makes sense.

    If you're calling something in a class method then there must be an
    instance of that class, instantiated as an object, in order to make the
    call in the first place.

    'self' does have meaning inside a class, you use it when you want to
    call another method within the same class. Python can then fill in the
    self reference in the arguments to the callee for you as it does when
    you call a method from outside of the class by qualifying with the
    instance name.
    inside class A:
    self.blah(args)
    outside class A:
    a_A = A()
    a_A.blah(args)

    Cheers,
    -B
    (Hope I've got this one right)
     
    , May 8, 2006
    #8
  9. John Salerno

    John Salerno Guest

    wrote:

    > I'm having trouble deciphering what this bit means - "but these
    > functions will be called from another method in the class, not from the
    > instance itself", I don't think it makes sense.


    Yeah, I'm starting to see that as I tried to implement it. Here's what I
    came up with, which works:

    def generate(self, filename):
    self.head = self.generate_head()
    self.body = self.generate_body()

    So the two generate_* methods are called from within another class
    method, and it seemed necessary to still call them from an instance.
    What I originally meant was that they would not be called from an
    instance *outside* the class itself, i.e. they won't be used when
    writing another script, they are only used by the class itself.
     
    John Salerno, May 8, 2006
    #9
  10. John Salerno

    Guest

    John Salerno wrote:
    > What I originally meant was that they would not be called from an
    > instance *outside* the class itself, i.e. they won't be used when
    > writing another script, they are only used by the class itself.


    Yep, so you want to encapsulate the functionality that those methods
    provide, which is the whole point of building them in a class in the
    first place. And you want them to be private to the class so that they
    do not form part of the classes public/external interface.

    In python, as discussed earlier :), you can make them semi-private by
    using the '__method_name' syntax. The thing is that python doesn't
    strictly enforce this privacy, code outside of your object can still
    call these methods because python just mangles the internal method name
    slightly. See
    http://docs.python.org/tut/node11.html#SECTION0011600000000000000000
    for more detail.

    Cheers,
    -B
     
    , May 8, 2006
    #10
  11. John Salerno

    John Salerno Guest

    wrote:
    > John Salerno wrote:
    >> What I originally meant was that they would not be called from an
    >> instance *outside* the class itself, i.e. they won't be used when
    >> writing another script, they are only used by the class itself.

    >
    > Yep, so you want to encapsulate the functionality that those methods
    > provide, which is the whole point of building them in a class in the
    > first place. And you want them to be private to the class so that they
    > do not form part of the classes public/external interface.


    But it's right that they should still be regular instance methods? So
    from within the class I still call them as self._generate_head(), etc.?
     
    John Salerno, May 8, 2006
    #11
  12. John Salerno

    John Salerno Guest

    John Salerno wrote:
    > wrote:
    >> John Salerno wrote:
    >>> What I originally meant was that they would not be called from an
    >>> instance *outside* the class itself, i.e. they won't be used when
    >>> writing another script, they are only used by the class itself.

    >>
    >> Yep, so you want to encapsulate the functionality that those methods
    >> provide, which is the whole point of building them in a class in the
    >> first place. And you want them to be private to the class so that they
    >> do not form part of the classes public/external interface.

    >
    > But it's right that they should still be regular instance methods? So
    > from within the class I still call them as self._generate_head(), etc.?


    I tried the underscore method, but I was still able to call it as a
    regular instance method in the interpreter. Is that what's supposed to
    happen?
     
    John Salerno, May 8, 2006
    #12
  13. tOn Mon, 08 May 2006 14:04:34 GMT, John Salerno
    <> declaimed the following in comp.lang.python:

    > I tried the underscore method, but I was still able to call it as a
    > regular instance method in the interpreter. Is that what's supposed to
    > happen?


    Single underscores are a convention/signal to the programmer that
    "this method/attribute" is considered "private" and should only be used
    by other methods within the class that defined it. The language does no
    enforcement of usage. For example:

    class Point(object):
    def __init__(self, x, y):
    # x, y are cartesian coordinates, but to be difficult
    # the point class will use polar coordinates internally
    self._rho = math.sqrt(x*x + y*y)
    self._theta = #some equation to determine angle from 0

    The single underscores tell the reader that rho and theta are to be
    considered private implementation details, and the user of the class
    should not rely on them being there. It should be possible to convert
    the class to using cartesian coordinates internally without affecting
    any USER -- the user interface (public methods/attributes/properties)
    should not change regardless of the internal implementation.


    Double underscores tell the compiler phase to do name-mangling so
    that the name stays class specific should the class be inherited...

    class A(object):
    def __init__(self, a_datum):
    super(A, self).__init__()
    self.__datum = a_datum

    class B(A):
    def __init__(self, b_datum):
    super(B, self).__init__(b_datam / 3.0)
    self.__datum = b_datum

    aB = B(33)

    Instance "aB" now has two attributes: _A__datum and _B__datum --
    both /can/ be accessed by anyone knowning the names.

    >>> dir(aB)

    ['_A__datum', '_B__datum', '__class__', '__delattr__', '__dict__',
    '__doc__', '__getattribute__', '__hash__', '__init__', '__module__',
    '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
    '__str__', '__weakref__']
    >>>
    >>> aB._A__datum

    11.0
    >>> aB._B__datum

    33

    If you used single underscores, there would only be a single
    "_datum" attribute, and it would have the last value assigned to it.

    >>>

    --
    Wulfraed Dennis Lee Bieber KD6MOG

    HTTP://wlfraed.home.netcom.com/
    (Bestiaria Support Staff: )
    HTTP://www.bestiaria.com/
     
    Dennis Lee Bieber, May 8, 2006
    #13
  14. John Salerno wrote:
    > John Salerno wrote:
    >> wrote:
    >>> John Salerno wrote:
    >>>> What I originally meant was that they would not be called from an
    >>>> instance *outside* the class itself, i.e. they won't be used when
    >>>> writing another script, they are only used by the class itself.
    >>>
    >>> Yep, so you want to encapsulate the functionality that those methods
    >>> provide, which is the whole point of building them in a class in the
    >>> first place. And you want them to be private to the class so that they
    >>> do not form part of the classes public/external interface.

    >>
    >> But it's right that they should still be regular instance methods? So
    >> from within the class I still call them as self._generate_head(), etc.?

    >
    > I tried the underscore method, but I was still able to call it as a
    > regular instance method in the interpreter. Is that what's supposed to
    > happen?


    If you called it, "__generate_head" you'd get more of what you expect.

    The Python philosophy is "we're all adults here," and the single leading
    underscore is meant to tell other users that the method is not for
    general use. Remember, you can't stop a user who insists on making
    mistakes. The double leading underscore is really meant for something
    else (names in "mixin" classes that don't accidentally collide with
    names in subclasses, for example).

    IMO, distutils, for example, over-uses the double leading underscore
    names; it makes it awkward for me to get to information that I'd like
    to obtain. The double leading underscore should be there if there is
    no reasonable use to getting to this info. I suspect leading double
    underscore names are more frequently written by Java and C++ fugitives
    who still have the "save the user from himself" attitude.

    --Scott David Daniels
     
    Scott David Daniels, May 8, 2006
    #14
  15. John Salerno

    John Salerno Guest

    Dennis Lee Bieber wrote:
    > tOn Mon, 08 May 2006 14:04:34 GMT, John Salerno
    > <> declaimed the following in comp.lang.python:
    >
    >> I tried the underscore method, but I was still able to call it as a
    >> regular instance method in the interpreter. Is that what's supposed to
    >> happen?

    >
    > Single underscores are a convention/signal to the programmer that
    > "this method/attribute" is considered "private" and should only be used
    > by other methods within the class that defined it. The language does no
    > enforcement of usage. For example:


    I see. But isn't there something about a single leading underscore that
    doesn't import when you use from X import *? Or am I thinking of
    something else? Is that also the double underscore?
     
    John Salerno, May 8, 2006
    #15
  16. John Salerno wrote:
    > Dennis Lee Bieber wrote:
    >> ... Single underscores are a convention/signal to the programmer that
    >> "this method/attribute" is considered "private" and should only be used
    >> by other methods within the class that defined it. The language does no
    >> enforcement of usage....

    >
    > I see. But isn't there something about a single leading underscore that
    > doesn't import when you use from X import *? Or am I thinking of
    > something else? Is that also the double underscore?


    That has to do with module contents, and is a completely separate issue.
    If you define a module with a variable name '__all__' which is a list
    (or tuple) of strings, only module elements with those names will be
    imported with a "from module import *". If you fail to define the
    '__all__' element, all names which do not start with an underscore will
    be imported.

    --Scott David Daniels
     
    Scott David Daniels, May 8, 2006
    #16
  17. John Salerno

    John Salerno Guest

    Scott David Daniels wrote:
    > John Salerno wrote:
    >> Dennis Lee Bieber wrote:
    >>> ... Single underscores are a convention/signal to the programmer that
    >>> "this method/attribute" is considered "private" and should only be used
    >>> by other methods within the class that defined it. The language does no
    >>> enforcement of usage....

    >>
    >> I see. But isn't there something about a single leading underscore
    >> that doesn't import when you use from X import *? Or am I thinking of
    >> something else? Is that also the double underscore?

    >
    > That has to do with module contents, and is a completely separate issue.
    > If you define a module with a variable name '__all__' which is a list
    > (or tuple) of strings, only module elements with those names will be
    > imported with a "from module import *". If you fail to define the
    > '__all__' element, all names which do not start with an underscore will
    > be imported.
    >
    > --Scott David Daniels
    >


    Thanks, that's what I was thinking of. So it doesn't apply to the
    contents within a class, just top-level contents?
     
    John Salerno, May 8, 2006
    #17
  18. John Salerno wrote:
    > Scott David Daniels wrote:
    >> John Salerno wrote:
    >>> ... But isn't there something about a single leading underscore
    >>> that doesn't import when you use from X import *? Or am I thinking of
    >>> something else? Is that also the double underscore?

    >>
    >> That has to do with module contents, and is a completely separate issue.
    >> If you define a module with a variable name '__all__' which is a list
    >> (or tuple) of strings, only module elements with those names will be
    >> imported with a "from module import *". If you fail to define the
    >> '__all__' element, all names which do not start with an underscore will
    >> be imported.

    >
    > Thanks, that's what I was thinking of. So it doesn't apply to the
    > contents within a class, just top-level contents?


    Precisely, a "from ... import *" only creates a bunch of names bound to
    a module's top-level contents (at the time of execution of the
    "from ... import *"), and does not affect anything about those bound
    values (except, of course, the refcount).

    --
    -Scott David Daniels
     
    Scott David Daniels, May 9, 2006
    #18
  19. John Salerno wrote:
    > John Salerno wrote:
    >
    >> wrote:
    >>
    >>> Even if you don't end up referring to self or any instance
    >>> attributes within the method

    >>
    >>
    >> Hmm, follow-up: I *do* plan to refer to instance attributes inside
    >> these methods (self.something), but does that require that they be
    >> instance methods, or can they still reference 'self' since they are
    >> inside the class?
    >>
    >> They won't be called directly from an instance, which is why I
    >> wondered about making them static or class methods, but can static or
    >> class methods use self, or does it have to be an instance method in
    >> that case?

    >
    >
    > Ugh, sorry about another post, but let me clarify: In these utility
    > functions, I need to refer to an attribute of an instance,


    So you want ordinary methods.

    > but these
    > functions will be called from another method in the class, not from the
    > instance itself.


    yes, they will:

    class Parrot(object):
    def _func1(self, whatever):
    print whatever

    def talk(self):
    self._func1('vroom')

    > Is this even possible, or would 'self' have no meaning
    > when used this way?


    You probably noticed that 'self' (or whatever you name it - but better
    to stick to convention) *must* be defined as the first param of a
    'method'. The reason for it is that what we commonly call 'methods' are
    in fact plain Python functions. It's only when they are looked up on an
    instance that they are wrapped into a 'method' object (read about the
    descriptor protocol to learn how...), that in turn calls the function,
    passing it the instance as first param.

    For saying it short (warning: over-simplification ahead), the usual
    method call idiom:

    myObj.myMethod(arg)

    is syntactic sugar for:

    myObj.__class__.myMethod(myObj, arg)


    HTH.

    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in ''.split('@')])"
     
    bruno at modulix, May 9, 2006
    #19
  20. John Salerno wrote:
    > wrote:
    >
    >> I'm having trouble deciphering what this bit means - "but these
    >> functions will be called from another method in the class, not from the
    >> instance itself", I don't think it makes sense.

    >
    >
    > Yeah, I'm starting to see that as I tried to implement it. Here's what I
    > came up with, which works:
    >
    > def generate(self, filename):
    > self.head = self.generate_head()
    > self.body = self.generate_body()
    >
    > So the two generate_* methods are called from within another class
    > method,


    here, generate() is *not* a class method, it's an instance method (which
    is the default).

    > and it seemed necessary to still call them from an instance.
    > What I originally meant was that they would not be called from an
    > instance *outside* the class itself, i.e. they won't be used when
    > writing another script, they are only used by the class itself.


    Yeps, that's pretty common in any OO language. In most mainstream OOPLs,
    these methods would have the 'protected' access restriction modifier. In
    Python, we rely on the convention that an attribute whose name is
    prefixed with a single underscore is an implementation detail - not part
    of the API - and should not be called by client code. Just renaming
    these two methods is enough to warn users of your code that they're on
    their own if they start messing with them.

    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in ''.split('@')])"
     
    bruno at modulix, May 9, 2006
    #20
    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. =?Utf-8?B?RGlmZmlkZW50?=

    "Page" class and utility class

    =?Utf-8?B?RGlmZmlkZW50?=, Jan 11, 2005, in forum: ASP .Net
    Replies:
    5
    Views:
    348
    =?UTF-8?B?IkFuZGVycyBOb3LDpXMgW01DQURdIg==?=
    Jan 11, 2005
  2. Martin Burger
    Replies:
    3
    Views:
    554
    Roland
    Jun 30, 2005
  3. Ian
    Replies:
    2
    Views:
    346
    Ulrich Petri
    Sep 6, 2003
  4. Replies:
    8
    Views:
    409
    Greg Herlihy
    Jun 28, 2008
  5. Phlip
    Replies:
    2
    Views:
    452
    phlip
    Jul 1, 2008
Loading...

Share This Page