8

If you type help(vars), the following is produced:

vars(...)
    vars([object]) -> dictionary

    Without arguments, equivalent to locals().
    With an argument, equivalent to object.__dict__.

When I do the following:

def func(x, y): pass

help(func)

it displays this:

func(x, y)

How can I change it so that it shows up with ... between the parentheses like the built-in function vars()? (That is, func(...))

Edit: It has been suggested to use a docstring, but that won't do what I want. Here is an example:

def func(x, y):
    """func(...) -> None"""

help(func)

result:

func(x, y)
    func(...) -> None

You see, x, y is still being displayed instead of ...

zondo
  • 19,901
  • 8
  • 44
  • 83
  • Give the function a `__doc__` attribute (docstring). – Håken Lid Feb 27 '16 at 03:21
  • 3
    That isn't quite the same thing. I'll edit my question to show you. – zondo Feb 27 '16 at 03:22
  • I think that that is not posible or at least is not that easy, some of the build-in functions have that because they are write in C so they escape the usual mechanism that the _help_ function use – Copperfield Feb 27 '16 at 03:55
  • 2
    Starting [here](https://github.com/python/cpython/blob/master/Lib/pydoc.py#L1352), you can see the conditions under which `pydoc.TextDoc.docroutine` (in Python 3.5, anyway) uses `(...)` to represent the signature of a callable. – chepner Feb 27 '16 at 04:49
  • 2
    A quick test shows that `xxx(...)` is the case for all the built-in functions. Following the hint from @chepner's comment, I looked to see what `inspect.getargspec(len)` returns, but it throws a TypeError with the message `TypeError: is not a Python function`. So it looks like any Python function *will* have an argspec, and so will get displayed with the args listed in their help. Short of implementing your `func` in C, it may not be possible to get this elliptical output. – PaulMcG Feb 27 '16 at 08:42
  • Just curious: Why would you _want_ this? – tobias_k Mar 13 '16 at 13:27
  • @tobias_k: I really don't expect every to use it, but I'm "just curious". – zondo Mar 13 '16 at 13:29
  • But then, shouldn't the question actually be "why do build-in function show `(...)` in `help`?" instead of "how can I replicate this?" – tobias_k Mar 13 '16 at 13:33
  • @tobias_k: I'm not sure why. What I am wondering is how I can replicate it. I don't expect to use that information, but I'd like to know how. – zondo Mar 13 '16 at 13:34

1 Answers1

8

You have (at least) two alternatives to achieve what you want.

The best alternative would be to override the __str__ method of the inspect.Signature class. However, as it is written in C, it is read only.

So to do that you need to extend the class as following:

class MySignature(inspect.Signature):
  def __str__(self):
    return '(...)'

then after defining your function you execute:

func_signature = inspect.signature(func)
func.__signature__ = MySignature(func_signature.parameters.values(), 
                                 return_annotation=func_signature.return_annotation)

which would then return the following for help(func):

Help on function func in module __main__:

func(...)
(END)

With this approach inspect.signature still works:

In [1]: inspect.signature(func)
Out[1]: <MySignature (...)>

Alternatively if you don't really care about being able to properly introspect your function (and probably some other use cases), then you can define the value of your function's __signature__ to an object which is not a Signature instance:

def func(x, y):
    pass

func.__signature__ = object()

help(func)

generates the result:

Help on function func in module __main__:

func(...)
(END)

But now inspect.signature(func) will raise TypeError: unexpected object <object object at 0x10182e200> in __signature__ attribute.

Note: this last version is quite hacky and I would not recommend it.

For more info on these two techniques and how the signature works see PEP 0362.

Update: For python 2.7 you can do the following (probably better using a mock framework):

In [1]: import inspect

In [2]: def myformatargspec(*args, **kwargs):
   ...:     return '(...)'
   ...:

In [3]: def func(x, y):
   ...:     pass
   ...: 

In [6]: inspect.formatargspec = myformatargspec

In [7]: help(func)

Help on function func in module __main__:

func(...)
(END)
Sebastian Kreft
  • 7,819
  • 3
  • 24
  • 41