Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > access __doc__ from within function without reference to function name

Reply
Thread Tools

access __doc__ from within function without reference to function name

 
 
SanPy
Guest
Posts: n/a
 
      10-02-2007
The subject of this message might be a little cryptic, so here's an
example of what I mean:

def foo():
"""doc string of foo"""
print foo.__doc__

>>> foo()

doc string of foo

What I want to know is whether it is possible to call __doc__ against
some builtin method, like __func__ or something like that. So calling
__doc__ without the functions name, something like this:

def foo():
"""doc string of foo"""
print __func__.__doc__ # pseudo code

So basically, my question is: is there a way to access a function from
within itself without using its name?

Regards, Sander.

 
Reply With Quote
 
 
 
 
Duncan Booth
Guest
Posts: n/a
 
      10-02-2007
SanPy <> wrote:

> So basically, my question is: is there a way to access a function from
> within itself without using its name?
>

Not really, no. Python is executing a code block, it has no idea which
function referenced that code block.

You can get the current code object quite easily (inspect.currentframe
().f_code), but the reference from function to code is one way: a single
code object could be used by multiple functions.

You can get the source code though, so if you are desperate enough you
could try parsing the source code to extract the docstring:

print inspect.getsource(inspect.currentframe())

Use the name of the function, that's the best way.
 
Reply With Quote
 
 
 
 
Tim Chase
Guest
Posts: n/a
 
      10-02-2007
> The subject of this message might be a little cryptic, so here's an
> example of what I mean:
>
> def foo():
> """doc string of foo"""
> print foo.__doc__
>
>>>> foo()

> doc string of foo
>
> What I want to know is whether it is possible to call __doc__ against
> some builtin method, like __func__ or something like that. So calling
> __doc__ without the functions name, something like this:
>
> def foo():
> """doc string of foo"""
> print __func__.__doc__ # pseudo code
>
> So basically, my question is: is there a way to access a function from
> within itself without using its name?



Well, I don't know if it's the best way to do it, but the
following code I just threw together does the trick for me:

################################################## #########
"A module docstring"
import inspect
def get_doc_string():
frame = inspect.stack()[1]
funcname = frame[3]
try: # for straight functions
return eval(funcname).__doc__
except:
locals = frame[0].f_locals
try: # for object methods
return getattr(locals["self"], funcname).__doc__
except:
try: # for class and module docstrings
return locals["__doc__"]
except:
print "If you got here, there's something I missed"
import pdb; pdb.set_trace()
return funcname

if __name__ == "__main__":

def outer_function():
"A function docstring"
s = get_doc_string()
print s
return s

class Foo(object):
"A class docstring"
zip = get_doc_string()
def bar(self):
"A method's docstring"
s = get_doc_string()
print s
return s

def f1(func):
"this is f1"
s = func()
print s
return s

test = outer_function()
assert test == "A function docstring"
foo = Foo()
assert foo.bar() == "A method's docstring"
print Foo.zip
assert Foo.zip == "A class docstring"
module_docstring = get_doc_string()
print module_docstring
assert module_docstring == "A module docstring"
assert f1(get_doc_string) == "this is f1"

################################################## #########

I couldn't find a handy way to get the actual
function-object/class-object/module/method object for the given
context without the convoluted try/except block. Perhaps someone
with more knowledge of the inspect module could reudce that do
something far more simple. There may also be problems if this is
imported across modules. But this might help point you in the
right direction.

-tkc




 
Reply With Quote
 
Duncan Booth
Guest
Posts: n/a
 
      10-02-2007
Tim Chase <> wrote:

>> So basically, my question is: is there a way to access a function from
>> within itself without using its name?

>
>
> Well, I don't know if it's the best way to do it, but the
> following code I just threw together does the trick for me:


The original request was to do it without using the function's name, but
you are depending on that name so your code is easy enough to break. e.g.
change the definition of f1 to:

def f2(func):
"this is f1"
s = func()
print s
return s
f1 = f2
del f2

and the output is:

A function docstring
A method's docstring
A class docstring
A module docstring
If you got here, there's something I missed
> c:\temp\docstring.py(1get_doc_string()

-> return funcname
(Pdb)
 
Reply With Quote
 
Tim Chase
Guest
Posts: n/a
 
      10-02-2007
> The original request was to do it without using the function's
> name, but you are depending on that name so your code is easy
> enough to break. e.g. change the definition of f1 to:
>
> def f2(func):
> "this is f1"
> s = func()
> print s
> return s
> f1 = f2
> del f2


Even Python-proper seems to get "confused" by this (though I
would contend it's correct behavior):


===================================
def f1():
raise Exception
f2 = f1
del(f1)
f2()
===================================


The traceback references f1() instead of f2. (other printing than
the calling line of code from the python file itself)


===================================
Traceback (most recent call last):
File "x.py", line 5, in ?
f2()
File "x.py", line 2, in f1
raise Exception
Exception
===================================

pdb suffers the same problem:

===================================
def f1():
import pdb; pdb.set_trace()
print 'hello'
f2 = f1
del(f1)
f2()
===================================


then, when run, use "where" to ask where Python thinks you are:


===================================
> c:\temp\z.py(3)f1()

-> print 'hello'
(Pdb) where
c:\temp\z.py(7)?()
-> f2()
> c:\temp\z.py(3)f1()

-> print 'hello'
===================================

It thinks we're in f1 as well even though f1 no longer exists.


My understanding was that the OP wanted a way to refrain from
hard-coding the function-name into the body of the function,
rather than to completely avoid the name of the function ever
being used anywhere.

Unless there's a mapping that I couldn't find (that would take
the current frame and map it to the calling
function/method/module object) the only way to completely avoid
this (AFAICT) would be to take the location information returned
by the stack frame, parse the file, and extract the doc-string
from the resulting line(s).

It gets hairier when the python is poorly written as one could
have pessimal cases of "valid" python docstrings that look like

def f(x): "docstring"; return x*2

or

def f(x):
"docstring"; return x*2

or common multiline items like

def f(x):
"""docstring1
docstring2"""
pass

or even worse,

def f(x):
"""this is a \"""docstring\"""
with \\\"""and\""" mutliple lines"""
pass

def f(x):
"this is\
a docstring"
pass

The parser also has to accomodate "raw" and "unicode" string
prefixes, as they're valid too:

def f(x):
r"raw!"
pass

def f(x):
u"Unicode"
pass


in addition. Okay...in most of these cases, the pathological
coder should be taken out back and beaten, but it's a non-trivial
problem

-tkc




 
Reply With Quote
 
Duncan Booth
Guest
Posts: n/a
 
      10-02-2007
Tim Chase <> wrote:

> The parser also has to accomodate "raw" and "unicode" string
> prefixes, as they're valid too:
>
> def f(x):
> r"raw!"
> pass
>
> def f(x):
> u"Unicode"
> pass
>
>
> in addition. Okay...in most of these cases, the pathological
> coder should be taken out back and beaten, but it's a non-trivial
> problem


Fortunately someone already wrote a parser for Python code, so it is pretty
trivial:

>>> import compiler
>>> class Visitor(compiler.visitor.ASTVisitor):

def visitFunction(self, node):
print node.doc

>>> def showdoc(source):

compiler.walk(compiler.parse(source), Visitor())


>>> showdoc(r'''def f(x):

"""this is a \"""docstring\"""
with \\\"""and\""" mutliple lines"""
pass
''')
this is a """docstring"""
with \"""and""" mutliple lines
>>> showdoc(r'''def f(x):

u"Unicode" " with concatenation"
pass
''')
Unicode with concatenation
>>>

 
Reply With Quote
 
Gabriel Genellina
Guest
Posts: n/a
 
      10-03-2007
En Tue, 02 Oct 2007 19:01:27 -0300, wang frank <>
escribi�:

> I am writing Python script now. The project will grow bigger in future.
> I need to import some packages for several functions, such as numpy.
> Where is the best plalce to put the import numpy command? Is it fine to
> put on the first line in the file?


Yes, this is the usual way.

> Is it better to put it into each function after the def functionname? or
> they are the same.


I only place an import inside a function when it's expensive (e.g. loads a
lot of things) and not always required, or when it's irrelevant to the
main purpose of the module (e.g. "import traceback" when it's used just to
handle some special exceptions).

> Since numpy function will be used in all files, so I have to import it
> in each files. Does this will increase the memory usuage or there are
> better way to do it.


No. Only the first import actually has to load the module; later imports
quickly return a reference to the already loaded module.

--
Gabriel Genellina

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Minor bug in tempfile module (possibly __doc__ error) James T. Dennis Python 9 05-11-2007 07:25 AM
Printing __doc__ gtb Python 7 03-22-2007 04:36 PM
__doc__ in compiled script Gabriel Genellina Python 5 11-03-2006 09:14 AM
property __doc__ David Isaac Python 1 07-01-2006 03:48 AM
__doc__ of current function? Trevor Taylor Python 3 09-02-2004 11:51 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57