Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python docstrings are unexpectedly None [closed]

When I create a class with method like this:

class Foo:
    """ A class """
    def bar():
        " Hello world "
        pass

I would expect the __doc__ to return the first statement of the method, since both are strings. Unfortunately, this does not happen:

print(Foo.__doc__)
print(Foo().__doc__)
print(Foo.bar.__doc__)
print(Foo().bar.__doc__)

outputs None 4 times. Also the example here

https://docs.python.org/3.4/library/functools.html?highlight=doc#functools.wraps

seems to fail, as the docstring is None for me:

from functools import wraps
def my_decorator(f):
    @wraps(f)
    def wrapper(*args, **kwds):
        print('Calling decorated function')
        return f(*args, **kwds)
    return wrapper

@my_decorator
def example():
    """Docstring"""
    print('Called example function')
print(example.__doc__)

Which also prints None.

Why are the __doc__'s not set to the specified strings?

ideone snipplet: http://ideone.com/cZNUQe

like image 696
Herbert Avatar asked Apr 18 '26 11:04

Herbert


1 Answers

Update: Based on @user2357112's suggestion, I found a way to reproduce ideone's behavior in a local interpreter, and it's likely the cause for the weird discrepancies. Specifically, it looks like ideone is running a wrapper script in Python without the -OO flag, but using the compile builtin function to compile the user provided code with optimize=2 as the argument, then evaling the resulting compiled code object. It looks like this causes the the split behavior previously mentioned; sys.flags.optimize is 0, and __debug__ is True (matching the state of the outer interpreter), but docstrings and assert statements are stripped (matching the optimization level used when compile is called).

To reproduce, run the following script with Python without passing the -OO flag:

source = '''import sys
print(sys.flags)
print("Debug:", __debug__)
if __debug__:
    print("Debug")
else:
    print("Non-debug")
class Foo:
    """abc"""
print("Foo docstring:", Foo.__doc__)
assert True == False
'''

compiled = compile(source, '<test>', 'exec', optimize=2)
eval(compiled)

The output is:

sys.flags(debug=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, verbose=0, bytes_warning=0, quiet=0, hash_randomization=1, isolated=0)
Debug: True
Non-debug
Foo docstring: None

where the first two lines behave as if running without -OO, while the next two lines (and the absence of an AssertionError) behave as if -OO is in effect. It looks like sys.flags checks are performed at runtime (which means they reflect the main interpreter state), __debug__ is half and half (if checks and possibly other conditional logic is performed at compile time, while other usage is runtime, note how __debug__ prints as True, but tests as False), while stripping docstrings and asserts is finished entirely during compilation (so they reflect the state of compile's optimize flag).


Old answer that applies more often outside ideone:

For non-ideone cases, behavior like this would indicate you're running with the -OO switch (double optimized). When run with -OO, docstrings are stripped during byte code compilation, replaced with None; setting PYTHONOPTIMIZE environment variable to 2 would have the same effect.

like image 200
ShadowRanger Avatar answered Apr 21 '26 01:04

ShadowRanger



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!