docstring that use globals?

K

kj

Consider the following Python snippet:

SEPARATOR = '+'

def spam(ham, eggs):
"""Return a hash of ham and eggs.

The variables ham and eggs are tuples of strings. The returned
"hash" is a dict made from the pairs returned by zip(ham, eggs).
If ham contains repeated keys, the corresponding values in eggs
are concatenated using the string "SEPARATOR".

For example, spam(('a', 'b', 'a'), ('x', 'y', 'z')) returns
{'a': 'xSEPARATORz', 'b': 'y'}."""

# implementation follows...


Of course, as written, the docstring above is no good. All
occurrences of the string "SEPARATOR" in it should be replaced with
the actual value of the global variable SEPARATOR, which in this
case is the string '+'.

My first attempt at achieving this effect was the following:

SEPARATOR = '+'

def spam(ham, eggs):
"""Return a hash of ham and eggs.

The variables ham and eggs are tuples of strings. The returned
"hash" is a dict made from the pairs returned by zip(ham, eggs).
If ham contains repeated keys, the corresponding values in eggs
are concatenated using the string "%(SEPARATOR)s".

For example, spam(('a', 'b', 'a'), ('x', 'y', 'z')) returns
{'a': 'x%(SEPARATOR)sz', 'b': 'y'}.""" % globals()

# implementation follows...


....which, of course (in retrospect), does not work, since only a
string literal, and not any ol' string-valued expression, at the
beginning of a function's body can serve as a docstring.

What's the best way to achieve what I'm trying to do?

(Of course, all these acrobatics are hardly worth the effort for
the simple example I give above. In the actual situation I'm
dealing with, however, there are a lot more docstrings and global
variables in the mix, and at this early stage of the development,
the values of the globals are still fluid. I'm trying to minimize
the effort required to keep the docstrings current, while still
retaining the freedom to adjust the values of the globals. Also,
FWIW, most of these globals are merely default values that can be
overridden at runtime.)

TIA!

~kj
 
M

MRAB

Consider the following Python snippet:

SEPARATOR = '+'

def spam(ham, eggs):
"""Return a hash of ham and eggs.

The variables ham and eggs are tuples of strings. The returned
"hash" is a dict made from the pairs returned by zip(ham, eggs).
If ham contains repeated keys, the corresponding values in eggs
are concatenated using the string "SEPARATOR".

For example, spam(('a', 'b', 'a'), ('x', 'y', 'z')) returns
{'a': 'xSEPARATORz', 'b': 'y'}."""

# implementation follows...


Of course, as written, the docstring above is no good. All
occurrences of the string "SEPARATOR" in it should be replaced with
the actual value of the global variable SEPARATOR, which in this
case is the string '+'.

My first attempt at achieving this effect was the following:

SEPARATOR = '+'

def spam(ham, eggs):
"""Return a hash of ham and eggs.

The variables ham and eggs are tuples of strings. The returned
"hash" is a dict made from the pairs returned by zip(ham, eggs).
If ham contains repeated keys, the corresponding values in eggs
are concatenated using the string "%(SEPARATOR)s".

For example, spam(('a', 'b', 'a'), ('x', 'y', 'z')) returns
{'a': 'x%(SEPARATOR)sz', 'b': 'y'}.""" % globals()

# implementation follows...


...which, of course (in retrospect), does not work, since only a
string literal, and not any ol' string-valued expression, at the
beginning of a function's body can serve as a docstring.

What's the best way to achieve what I'm trying to do?

(Of course, all these acrobatics are hardly worth the effort for
the simple example I give above. In the actual situation I'm
dealing with, however, there are a lot more docstrings and global
variables in the mix, and at this early stage of the development,
the values of the globals are still fluid. I'm trying to minimize
the effort required to keep the docstrings current, while still
retaining the freedom to adjust the values of the globals. Also,
FWIW, most of these globals are merely default values that can be
overridden at runtime.)
Use a decorator:

SEPARATOR = '+'

def expand_doc(func):
func.__doc__ = func.__doc__ % globals()
return func

@expand_doc
def spam(ham, eggs):
"""Return a hash of ham and eggs.

The variables ham and eggs are tuples of strings. The returned
"hash" is a dict made from the pairs returned by zip(ham, eggs).
If ham contains repeated keys, the corresponding values in eggs
are concatenated using the string "%(SEPARATOR)s".

For example, spam(('a', 'b', 'a'), ('x', 'y', 'z')) returns
{'a': 'x%(SEPARATOR)sz', 'b': 'y'}."""

# implementation follows...
 
P

Peter Otten

kj said:
Consider the following Python snippet:

SEPARATOR = '+'

def spam(ham, eggs):
"""Return a hash of ham and eggs.

The variables ham and eggs are tuples of strings. The returned
"hash" is a dict made from the pairs returned by zip(ham, eggs).
If ham contains repeated keys, the corresponding values in eggs
are concatenated using the string "SEPARATOR".

For example, spam(('a', 'b', 'a'), ('x', 'y', 'z')) returns
{'a': 'xSEPARATORz', 'b': 'y'}."""

# implementation follows...


Of course, as written, the docstring above is no good. All
occurrences of the string "SEPARATOR" in it should be replaced with
the actual value of the global variable SEPARATOR, which in this
case is the string '+'.

My first attempt at achieving this effect was the following:

SEPARATOR = '+'

def spam(ham, eggs):
"""Return a hash of ham and eggs.

The variables ham and eggs are tuples of strings. The returned
"hash" is a dict made from the pairs returned by zip(ham, eggs).
If ham contains repeated keys, the corresponding values in eggs
are concatenated using the string "%(SEPARATOR)s".

For example, spam(('a', 'b', 'a'), ('x', 'y', 'z')) returns
{'a': 'x%(SEPARATOR)sz', 'b': 'y'}.""" % globals()

# implementation follows...


...which, of course (in retrospect), does not work, since only a
string literal, and not any ol' string-valued expression, at the
beginning of a function's body can serve as a docstring.

What's the best way to achieve what I'm trying to do?

A simple way is

spam.__doc__ = spam.__doc__ % globals()

which can easily be turned into a decorator:

def update_doc(f):
f.__doc__ = f.__doc__ % f.func_globals
return f

@update_doc
def spam(...):
...

Peter
 
K

kj

In said:
MRAB, Peter: thanks for the decorator idea!


As an afterthought, is there any way to extend this general idea
to other docstrings beyond function docstrings?

I imagine that the decorator idea works well for method docstrings
too (though I have not tried any of this yet).

But, IIRC, decorators don't work for classes, so class docstrings
would need to be expanded expressly.

The hardest case is "module docstrings". In particular, the
docstring for a script. Is there any way to apply the globals
expansion idea to a script's toplevel docstring?

(I imagine the answer to this last question is "no", but I thought
I'd ask. :) )

~kj
 
C

Chris Rebert

As an afterthought, is there any way to extend this general idea
to other docstrings beyond function docstrings?

I imagine that the decorator idea works well for method docstrings
too (though I have not tried any of this yet).

But, IIRC, decorators don't work for classes

PEP 3129: Class Decorators
http://www.python.org/dev/peps/pep-3129/

It was approved and seems to have been backported to at least v2.6.6.

Cheers,
Chris
 
G

Gregory Ewing

kj said:
The hardest case is "module docstrings".

Actually, that one's quite easy, just assign to __doc__.

__doc__ = "This is a %s docstring" % "made-up"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top