[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)