[HN Gopher] The features of Python's help() function
       ___________________________________________________________________
        
       The features of Python's help() function
        
       Author : danso
       Score  : 141 points
       Date   : 2025-03-05 14:07 UTC (3 days ago)
        
 (HTM) web link (www.pythonmorsels.com)
 (TXT) w3m dump (www.pythonmorsels.com)
        
       | ape4 wrote:
       | Cool idea. Do any other languages have this?
        
         | jhbadger wrote:
         | R has probably the best help feature for any language -- not
         | only can you ask it about help on individual functions with
         | "?", the tradition (and this continues with most add in
         | packages as well as builtins) is not only does it give you info
         | on the function, it gives you example code using it so you can
         | understand what it does in practice.
        
         | emmelaich wrote:
         | utop for ocaml is cool, gives type signatures for functions. no
         | explicit help, but does offer completions with tab.
         | 
         | Similarly, rtop for reason.
         | 
         | https://opam.ocaml.org/blog/about-utop/ and
         | https://opam.ocaml.org/packages/rtop/
        
           | reycharles wrote:
           | I wrote a small thing for adding a `#doc List.find`
           | directive. However, I don't maintain it anymore since I think
           | it doesn't see much use and it's work to keep up on OCaml
           | compiler internals changes (and it's my impression it never
           | picked up much adoption). https://github.com/reynir/ocp-
           | index-top
           | 
           | dbuenzli's down also has a similar feature.
        
         | stevekemp wrote:
         | Like many others here I once wrote a toy lisp in golang, and I
         | added a help function. It would give usage-information for all
         | the built-in functions.                     > (help +)
         | Arguments N arg1..argN           Adds all arguments present to
         | the first number.                > (help map)
         | Arguments lst:list fun:function           Return a list with
         | the contents of evaluating the given function on every item of
         | the supplied list.           See-also: map-pairs
        
         | freedomben wrote:
         | Ruby has a similar help() function you can invoke from the REPL
         | (irb), or from the CLI with the standalone tool `ri`[1]. Pretty
         | nifty feature!
         | 
         | [1]: https://stackoverflow.com/a/25671404
        
         | chillpenguin wrote:
         | Smalltalk, by far, is the best in this category.
        
         | mechanicum wrote:
         | Clojure has doc and source functions. For example:
         | user=> (doc clojure.core)       -------------------------
         | clojure.core         Fundamental library of the Clojure
         | language            user=> (doc +)
         | -------------------------       clojure.core/+       ([] [x] [x
         | y] [x y & more])         Returns the sum of nums. (+) returns
         | 0. Does not auto-promote         longs, will throw on overflow.
         | See also: +'            user=> (source +)       (defn +
         | "Returns the sum of nums. (+) returns 0. Does not auto-promote
         | longs, will throw on overflow. See also: +'"         {:inline
         | (nary-inline 'add 'unchecked_add)         :inline-arities >1?
         | :added "1.2"}         ([] 0)         ([x] (cast Number x))
         | ([x y] (. clojure.lang.Numbers (add x y)))         ([x y &
         | more]           (reduce1 + (+ x y) more)))
        
         | JadeNB wrote:
         | Although it's probably not at the top of many people's minds
         | (includind mine) as a favorite programming language,
         | Mathematica does have fantastic help, accessible with `?` and
         | expandable from there as needed.
        
       | viccis wrote:
       | help() is great, but my favorite tool for getting quick info
       | about an object from the Python REPL is still wat.
       | 
       | Just `pip install wat` and then if you need info about some
       | object o, do `wat / o`. If you want full docstrings, do `wat.long
       | / o`
       | 
       | It's a lifesaver when you're using a poorly documented package.
        
         | kstrauser wrote:
         | Dear god: https://github.com/igrek51/wat?tab=readme-ov-
         | file#load-from-...
        
           | extraduder_ire wrote:
           | I always think of python as a more readable version of perl.
           | I first got that impression from the "import this" statement.
           | 
           | That load from glyph snippet aligns with my understanding.
        
             | kstrauser wrote:
             | For the record, this is not what I would consider idiomatic
             | Python.
        
       | ks2048 wrote:
       | Some room for improvement on getting help for symbols:
       | 
       | help("**") explains the power operator, but could also mention
       | dict unpacking.
       | 
       | help("<<") doesn't mention bit shifting (shows a page for
       | "operator precedence").
       | 
       | I was going to say languages should emphasize help for symbols
       | because they're hard to Google for - but I guess in the LLM age,
       | that's no longer true.
        
         | emmelaich wrote:
         | Also uses / in the method signatures with no indication of what
         | it means.
         | 
         | This article doesn't either.
         | 
         | Apparently "It signifies the end of the positional only
         | parameters, parameters you cannot use as keyword parameters."
         | 
         | Which is redundant for most functions as they only have
         | positional parameters.
        
           | hermitdev wrote:
           | > Which is redundant for most functions as they only have
           | positional parameters.
           | 
           | Huh? This is not true.                   def foo(a, b, c):
           | ...
           | 
           | This can be invoked as either `foo(1, 2, 3)` or `foo(c=3,
           | b=2, a=1)`:                   >>> def foo(a, b, c):
           | ...     print(f"{a=}")         ...     print(f"{b=}")
           | ...     print(f"{c=}")         ...         >>> foo(1, 2, 3)
           | a=1         b=2         c=3         >>> foo(c=3, b=2, a=1)
           | a=1         b=2         c=3         >>>
        
             | emmelaich wrote:
             | Help on built-in function sin in module math:
             | sin(x, /)             Return the sine of x (measured in
             | radians).                     >>> math.sin(x=2)
             | ~~~~~~~~^^^^^           TypeError: math.sin() takes no
             | keyword arguments
             | 
             | / is used everwhere and it's usually just noise.
             | Unexplained noise.
        
               | mananaysiempre wrote:
               | It is often used _for builtins_ , because emulating the
               | default Python behaviour of accepting arguments both by
               | position and by name is a pain with the Python/C API.
               | (There are other use cases for positional-only arguments,
               | such as accepting an arbitrary function and an arbitrary
               | set of arguments to call it with at the same time--for
               | example, to invoke it in a new coroutine--but they are
               | pretty rare.) This pecularity of most builtin functions
               | has been there since before Python 3 was a thing, it's
               | just been undocumented and difficult to emulate in Python
               | before this syntax was introduced.
               | 
               | As for unexplained noise--well, all other parts of the
               | function declaration syntax aren't explained either.
               | You're expected to know the function declaration syntax
               | in order to read help on individual function
               | declarations; that's what the syntax reference is for.
        
               | emmelaich wrote:
               | How would you discover the syntax reference via the repl
               | help() system?
        
               | emmelaich wrote:
               | Found it.
               | 
               | >>> help('def')
        
           | aftbit wrote:
           | Ooh that feature was new to me. See PEP 570[1] for more
           | details. My personal opinion is that this is not something
           | that any code should do... but I'm not the BDFL!
           | 
           | 1: https://peps.python.org/pep-0570/
        
           | masklinn wrote:
           | > Which is redundant for most functions as they only have
           | positional parameters.
           | 
           | It would not need to exist if that were the case.
           | 
           | The "default" in Python is that a parameter can be passed
           | both positionally and by keyword. Until Python 3.8, the only
           | way to have positional only parameters in pure Python was to
           | use *args and unpack them yourself.
        
             | thaumasiotes wrote:
             | Why does it need to exist even though that's not the case?
             | 
             | What's the advantage of stopping someone from naming the
             | parameter when they pass it in?
        
               | apple1417 wrote:
               | Reading the PEP for adding it, it seems primarily
               | concerned with mirroring how the C builtins generally
               | don't allow it, for performance.
               | 
               | https://peps.python.org/pep-0570/#rationale
               | 
               | That being said, you can find quite a lot of uses in the
               | modules written in Python - though I'm not going to
               | pretend I can tell you the reasoning for all them.
               | grep "/\s*[,)]" /usr/lib/python3.13/ --recursive
               | --include "*.py" --exclude-dir site-packages
               | 
               | In my own code, the main use I've found is that they
               | don't "reserve" a slot in kwargs - this is totally valid
               | code:                 def func(x, /, **kwargs):
               | print(x, kwargs)       func(1, x=2)
               | 
               | You could've worked around it by taking a dict before,
               | but it's just a lot friendlier being able to take args as
               | normal.
        
               | rtpg wrote:
               | I did not know that about kwargs! Very interesting and
               | useful to be kind of pedantic and not have unintentional
               | conflicts at that level
        
               | masklinn wrote:
               | > What's the advantage of stopping someone from naming
               | the parameter when they pass it in?
               | 
               | There are cases where a parameter name is worthless on
               | the calling side, this is especially common for unary or
               | binary functions.
               | 
               | In that case, the ability to name the parameter on the
               | call site just constrains the implementation, and the
               | overrides (in the case of methods).
        
               | IgorPartola wrote:
               | Right. For example, something like max() or abs() have no
               | meaningful parameter names. But for example max() does
               | take a `key` named argument as well.
        
               | ok_dad wrote:
               | Edit: this is wrong, I was thinking/merging the idea of
               | the '*' into this one, my bad.
               | 
               | -- original below --
               | 
               | > What's the advantage of stopping someone from naming
               | the parameter when they pass it in?
               | 
               | From what I have seen, this feature is mostly used for
               | the opposite direction, to force the caller to use
               | keyword arguments past a certain number of (or zero)
               | positional arguments.
        
               | thaumasiotes wrote:
               | But that's *, not /.
        
               | ok_dad wrote:
               | yep!
        
               | alkh wrote:
               | When parameter names are meaningless for the final result
               | def abs_days_difference(date1, date2, /):         # note
               | that swapping passed params will yield the same result
               | delta = abs((date2 - date1).days)         return delta
               | d1 = date(2023, 1, 1)       d2 = date(2024, 1, 15)
               | abs_days_difference(d1,d2)==abs_days_difference(d2,d1)
               | 
               | The function returns the absolute diff in the number of
               | days, so date1, date2 are meaningless variable names. It
               | looks like then introduce an order(could #1 be the
               | earlier date, while #2 be the later one?). If you don't
               | get users any options it is clear that the order is
               | meaningless
               | 
               | Compare with                 def
               | day_difference(earlier_date, later_date):
               | delta = (later_date - earlier_date).days         return
               | delta
               | 
               | Note that now                 d1 = date(2023, 1, 1)
               | d2 = date(2024, 1, 15)
               | day_difference(d1,d2)!=day_difference(d2,d1)
               | 
               | If you function signature is day_difference(date1,
               | date2,*) you have to specify params as kwargs only,
               | removing the confusion:                 d1 = date(2023,
               | 1, 1)       d2 = date(2024, 1, 15)       #this now
               | doesn't work       day_difference(d1,d2)       # this
               | works and is much clearer for caller
               | day_difference(earlier_date=d1,later_date=d2)
        
           | rat87 wrote:
           | It's not redundant because regular python parameters without
           | a / in the list can be called by name even if they don't have
           | default values. The author may intend them to be positional
           | only but some callers might call them by name and you might
           | break them when you refactor the parameter names, positional
           | only avoids that. Some people dislike positional only
           | parameters but they're already used in a number of stdlib
           | functions written in c so it makes sense to be able to write
           | replacement with the same semantics in pure python as well as
           | being able to express signatures for the c function
        
             | emmelaich wrote:
             | That is simply and obviously not true. See my example for
             | math.sin above.
        
           | emmelaich wrote:
           | My major point still stands.
           | 
           | 1. It's useless noise for something like help(math.sin).
           | 
           | 2. It's everywhere and not well documented. Ironical for a
           | help system!
           | 
           | Damn it's been hard to improve Python's help system. Python2
           | didn't have an entry for re.MatchObject. When I mentioned
           | this on irc #python the response was to just google it. Talk
           | about not getting the point. help() should help.
        
             | chthonicdaemon wrote:
             | It is not useless noise for something like
             | `help(math.sin)`. The signature displayed by help is
             | `sin(x, /)`, which tells you that `sin(x=1)` will fail. If
             | the signature had just been `sin(x)` then `sin(x=1)` would
             | work.
        
               | emmelaich wrote:
               | OK you're right. But it wouldn't even have occurred to me
               | to try sin(x=2) until I read sibling comment.
        
               | adammarples wrote:
               | I guess that's because you don't know how function
               | arguments work in python but that's not really the fault
               | of the help documentation
        
               | emmelaich wrote:
               | Astonishing. As if help() cannot be improved and this is
               | not a 'fault'.
        
               | throwaway127482 wrote:
               | help() should not have to re-teach you the syntax of the
               | language every time you look up an individual help topic,
               | though. Even though this "/" stuff is uncommonly used, it
               | seems like it should have its own help topic. Otherwise,
               | this means that help() has to re-explain every piece of
               | syntax that might be considered "uncommonly used", which
               | is kind of hard to draw a line for.
        
           | _Algernon_ wrote:
           | The default for python function is that params can be
           | specified as either positional or keyword. / makes params
           | before it positional only while * makes params after it
           | keyword only.
        
       | tclancy wrote:
       | Nice. I usually fall back to dir() as my first inspection tool at
       | the command line.
        
         | mdaniel wrote:
         | or its awesome two friends: locals() and globals() to see their
         | names and values simultaneously; I've gotten a lot of mileage
         | out of that as a pseudo-debugger when the only insight you have
         | is a logger in production
        
           | kstrauser wrote:
           | Don't forget `vars()`.
        
         | analog31 wrote:
         | I bounce back and forth. First dir() then help()...
        
         | bayesianbot wrote:
         | I used to, but wat offers a better printout of the methods:
         | https://github.com/igrek51/wat
        
         | infamia wrote:
         | vars() is another good one if you're looking for something with
         | a particular value.
        
       | shawnz wrote:
       | > There are other ways to use the help function, but before we
       | dive into those I'd like to address the *, and / symbols shown in
       | the output above.
       | 
       | Where is this addressed? Is there a section missing here?
        
         | mdaniel wrote:
         | I am posting this because I always forget which one it is and
         | searching for it is damn near impossible
         | 
         | https://peps.python.org/pep-0457/#syntax-and-semantics
         | 
         | "/" marks the boundary between "positional only" and "mixed"
         | and then "*" does the same for "mixed" and "kwargs only"
        
       | nayuki wrote:
       | The web page's stylesheet is broken (returns HTTP 404) but the
       | text is still quite readable. Good job!
        
       | btdmaster wrote:
       | An interesting side effect is that it runs the code inside the
       | module you import, so that code can act based on whether it gets
       | imported by help or not:
       | 
       | https://tio.run/##VY6/DoIwEMb3PsUXl6ODLK7ETVcfwBhylBqIpW1KB3...
        
       | rzzzt wrote:
       | Before 3.13: https://thejenkinscomic.net/?id=52
        
       | PyWoody wrote:
       | If you use Vim, SHIFT+K will bring up the help docstring for the
       | object under your cursor. If you want `method`'s help from
       | `object.method`, all you have to do is highlight `object.method`
       | then do SHIFT+K.
       | 
       | The navigation is a little awkward but it's super handy for quick
       | one-offs right in the buffer.
        
         | otherayden wrote:
         | Thank you for this, super handy
        
       | chthonicdaemon wrote:
       | For quick lookups, I usually use pydoc[1], which displays roughly
       | the same help string but without having to go into the repl. I
       | think there are several *doc functions like this. Off the top of
       | my head I can think of texdoc (which usually just opens the pdf
       | of the package documentation) and perldoc.
       | 
       | pydoc -b is also very useful as a standard lib reference when
       | you're not connected to the internet and you can live with the
       | quite interesting default color scheme.
       | 
       | [1] https://docs.python.org/3/library/pydoc.html
        
       ___________________________________________________________________
       (page generated 2025-03-08 23:01 UTC)