access __doc__ from within function without reference to function name

S

SanPy

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__
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.
 
D

Duncan Booth

SanPy said:
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.
 
T

Tim Chase

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__

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
 
D

Duncan Booth

Tim Chase said:
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(18)get_doc_string()
-> return funcname
(Pdb)
 
T

Tim Chase

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
 
D

Duncan Booth

Tim Chase said:
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:
def visitFunction(self, node):
print node.doc
compiler.walk(compiler.parse(source), Visitor())

"""this is a \"""docstring\"""
with \\\"""and\""" mutliple lines"""
pass
''')
this is a """docstring"""
with \"""and""" mutliple lines u"Unicode" " with concatenation"
pass
''')
Unicode with concatenation
 
G

Gabriel Genellina

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.
 

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

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top