Why python docstring is interpreted differently from comment - python

Let's say, I've got a function like this:
def myFunc():
# useful function to calculate stuff
This will produce an indentation error, unless I add pass:
def myFunc():
# useful function to calculate stuff
pass
However, if I replace a comment with docstring, no pass is necessary:
def myFunc():
"""useful function to calculate stuff"""
This seems like an odd feature as neither of these are used in the program, as far as I know. So, why does it behave like this?

A comment is outright ignored by the interpreter, so omitting a block after an indent is a syntax error. However, a docstring is a real Python object--at its most basic, a literal str. A lone expression is a valid block of code:
'This is a string. It is a valid (though pretty useless) line of Python code.'
In the case of docstrings in particular, there's also some additional functionality going on, such as being used to set the __doc__ attribute.
>>> def myFunc():
... '''MyDocString'''
...
>>> print(myFunc.__doc__)
MyDocString
Note that this also works for classes:
>>> class MyClass(object):
... '''MyClassDocString'''
...
>>> print(MyClass.__doc__)
MyClassDocString

A docstring isn't just a comment. It actually has meaning to the interpreter. In the case with a docstring, you could do myFunc.__doc__ and actually get your docstring back (In the other case with a pass, the result myFunc.__doc__ would be None).
In other words, you are actually adding some code to the function body to modify it's behavior (in some circumstances), so no pass is necessary.

Related

Technical differences in doing nothing vs. pass "" [duplicate]

Are these equivalent?
class Empty : pass
and
class Empty:
'''
This class intentionally left blank
'''
The second one seems better for readability and one could put pass at the end but it does not seem necessary.
Is the comment treated as a pass?
Your two codes are almost equivalent, but not quite. pass is just a no-op. The docstring is almost a no-op as well, but it adds a __doc__ attribute to your class object, so there is a small difference.
A version that would be functionally equivalent to using pass would be to use Ellipsis a.k.a. ...:
class Empty: ...
There is nothing special about ... in this case. Any pre-existing object that you don't assign will work just as well. For example, you could replace ... with None, 1, True, etc. The choice of ... is a popular alternative because it is much more aesthetically pleasing. By convention, it means a stub that is to be filled in, while pass usually indicates a deliberate no-op.
Using ... like that will raise a SyntaxError in Python 2. You can use the named Ellipsis object instead, but that is not nearly as pretty.
You may also find this question about the equivalence of pass and return None in functions interesting.
No, they're not equivalent.
Since the implementation of PEP 257, if the first expression in a module, function, or class is a string, that string will be assigned to that module/function/class's __doc__ attribute:
A docstring is a string literal that occurs as the first statement in
a module, function, class, or method definition. Such a docstring
becomes the __doc__ special attribute of that object.
Functionally, the classes are equivalent. However, the difference between having a docstring and not having a docstring can surface when you're creating documentation for your code. Tools like sphinx-autodoc can pick up the docstring and generate documentation for your class, and you'll end up with something like this in your documentation:
class Empty()
This class intentionally left blank
For this reason, it's generally preferable not to use a docstring for this kind of thing. Instead, it would be better to use a comment:
class Empty:
pass # This class intentionally left blank

Why does Python ignore comment indentation?

Apparently, this:
def f():
pass
# maybe the function is over
pass # oh wait, it's not
f()
is valid syntax, whereas this is not:
def f():
pass
''' maybe the function is over '''
pass # oh wait, it's not
f()
That comes as a huge surprise to me. So my questions are:
Why? Why does Python not consider the first version to be a syntax error?
Is there anything in PEP8 recommending that this not be done?
Yes the first one is valid because it starts with # which defined in the language to be a comment line so it's ignored and its indentation won't end functions or start new ones.
The latter is different, it's a string evaluated but its value is never used, you could use that to achieve multi line comments but still the interpreter will try to evaluate that string as code, so the indentation of this string matter to the interpreter and it could end scopes.
for the second one writing something like
'''comment''''
is as much code to the interpreter as this
my_var = '''comment'''
But this
# comment
is ignored and is not code to the interpreter.

Using string formatting within class method docstrings

I have a class with several similar methods, each with long docstrings that are similar but vary with regards to several phrases/words. I'd like to build a docstring template and then apply string formatting to it. Below is a clumsy implementation where the __doc__s are defined after the class methods.
capture_doc = """
%(direc)s normal.
a %(sym)s b."""
class Cls():
def a(self):
pass
def b(self):
pass
a.__doc__ = capture_doc % {'direc' : 'below', 'sym' : '<'}
b.__doc__ = capture_doc % {'direc' : 'above', 'sym' : '>'}
c = Cls()
print(c.a.__doc__)
below normal.
a < b.
Question: is there a Python docs- or PEP-prescribed way to do this? I'd like to keep things basic, I've seen use of an #Appender decorator but think that's a bit fancy for my needs.
You shouldn't do this. You seem to assume your docstring should only serve those who use your code and need help with how it works.
Docstrings are supposed to provide some form of the documentation for the associated object for those reading your code, so this makes your docstring half its worth. I doubt any one would love to go through the trouble of having to format those strings (in their heads or using the interpreter) to figure out what your code does or how it works.
From PEP 257:
What is a Docstring?
A docstring is a string literal that occurs as the first statement
in a module, function, class, or method definition. Such a docstring
becomes the __doc__ special attribute of that object.
[Emphasis mine]
With your implementation, one could pedantically argue you don't have docstrings albeit __doc__ attributes.

Stubbing out functions or classes

Can you explain the concept stubbing out functions or classes taken from this article?
class Loaf:
pass
This class doesn't define any methods or attributes, but syntactically, there needs to be something in the definition, so you use pass. This is a Python reserved word that just means “move along, nothing to see here”. It's a statement that does nothing, and it's a good placeholder when you're stubbing out functions or classes.`
thank you
stubbing out functions or classes
This refers to writing classes or functions but not yet implementing them. For example, maybe I create a class:
class Foo(object):
def bar(self):
pass
def tank(self):
pass
I've stubbed out the functions because I haven't yet implemented them. However, I don't think this is a great plan. Instead, you should do:
class Foo(object):
def bar(self):
raise NotImplementedError
def tank(self):
raise NotImplementedError
That way if you accidentally call the method before it is implemented, you'll get an error then nothing happening.
A 'stub' is a placeholder class or function that doesn't do anything yet, but needs to be there so that the class or function in question is defined. The idea is that you can already use certain aspects of it (such as put it in a collection or pass it as a callback), even though you haven't written the implementation yet.
Stubbing is a useful technique in a number of scenarios, including:
Team development: Often, the lead programmer will provide class skeletons filled with method stubs and a comment describing what the method should do, leaving the actual implementation to other team members.
Iterative development: Stubbing allows for starting out with partial implementations; the code won't be complete yet, but it still compiles. Details are filled in over the course of later iterations.
Demonstrational purposes: If the content of a method or class isn't interesting for the purpose of the demonstration, it is often left out, leaving only stubs.
Note that you can stub functions like this:
def get_name(self) -> str : ...
def get_age(self) -> int : ...
(yes, this is valid python code !)
It can be useful to stub functions that are added dynamically to an object by a third party library and you want have typing hints.
Happens to me... once :-)
Ellipsis ... is preferable to pass for stubbing.
pass means "do nothing", whereas ... means "something should go here" - it's a placeholder for future code. The effect is the same but the meaning is different.
Stubbing is a technique in software development. After you have planned a module or class, for example by drawing it's UML diagram, you begin implementing it.
As you may have to implement a lot of methods and classes, you begin with stubs. This simply means that you only write the definition of a function down and leave the actual code for later. The advantage is that you won't forget methods and you can continue to think about your design while seeing it in code.
The reason for pass is that Python is indentation dependent and expects one or more indented statement after a colon (such as after class or function).
When you have no statements (as in the case of a stubbed out function or class), there still needs to be at least one indented statement, so you can use the special pass statement as a placeholder. You could just as easily put something with no effect like:
class Loaf:
True
and that is also fine (but less clear than using pass in my opinion).

Writing docstrings - specifying functions arguments and returns

Suppose I have a function, say:
>>> def foo(a):
return a+1
I want to write a documentation string for it.
what is the convention in specifying in the docstring that it takes a and returns a+1?
The idea of a docstring is to give the user a basic overview of what's going in and coming out without telling them too much about how that happens. In this case:
def foo(a):
"""Take a number a and return its value incremented by 1."""
return a + 1
For a less trivial example, I like the one in Dive Into Python's section on documenting functions:
def build_connection_string(params):
"""Build a connection string from a dictionary of parameters.
Return string."""
Obviously, a more complicated function requires a bigger docstring. Just make sure the docstring is talking about what's happening (what's getting passed in, what's being returned) instead of how that's happening (implementation details should not be included).
PEP 257 should help!
For Python conventions (about this and other topics), I'd suggest first trying the Python Enhancement Proposals.
Python PEP 257 suggests for one line docstrings to specify your function like so:
def function(a, b):
"""Do X and return a list."""
but not like this:
def function(a, b):
"""function(a, b) -> list"""
because the latter example can be divined through other means.
Only glanced through them but the links from the PEP look to go to other PEP's that get into the nitty-gritty of docstrings.
As a general note I'd browse through the PEPs if you haven't yet as there are some interesting topics about Python design decisions and philosophy.
I personally like the style the builtins use.
>>> help(len)
len(...)
len(object) -> integer
Return the number of items of a sequence or mapping.

Categories

Resources