1

I tried to create a mock object like this, without wanting to manually specify the bases (since I don't need any bases):

>>> type('dummy_thing', dict={'dummy_attr': 'potato'})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type() takes 1 or 3 arguments

Normally if a kwarg can take a default it is written in the argspec, but this doesn't seem to always be the case.

>>> print(slice.__doc__)
slice(stop)
slice(start, stop[, step])
Create a slice object.  This is used for extended slicing (e.g. a[0:10:2]).

>>> print(complex.__doc__)
complex(real[, imag]) -> complex number
Create a complex number from a real part and an optional imaginary part.
This is equivalent to (real + imag*1j) where imag defaults to 0.

Here we have similar style argspec, complex is allowed to default real, imag, or both (the argspec behaves like complex(real=0, imag=0):

>>> complex(imag=7)
7j

Several builtins like for example slice, range, and surely many others, don't allow you to name the arguments:

>>> slice(stop=2)  # I expected to get a slice(None, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: slice() does not take keyword arguments

type doesn't let me name them even if I specify all three:

>>> type('', (), {})
<class '__main__.'>
>>> type('', bases=(), dict={})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type.__init__() takes no keyword arguments

Then, datetime has a similar argspec (the weird ones with square brackets) but doesn't mind taking kwargs:

>>> print(datetime.__doc__)
datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])
The year, month and day arguments are required. tzinfo may be None, or an
instance of a tzinfo subclass. The remaining arguments may be ints.
>>> datetime(year=2014, month=7, day=17)
datetime.datetime(2014, 7, 17, 0, 0)

Question: is there some rhyme or reason / consistency to when python allows you to use the defaults or not, to avoid these kind of surprises? Or is it really just trial and error, and having the familiarity with the language?

wim
  • 338,267
  • 99
  • 616
  • 750
  • This sounds like the issue where functions implemented in C don't take keyword arguments. http://bugs.python.org/issue16666 – Mikel Jul 17 '14 at 15:41
  • See also [Why does str.split not take keyword arguments?](http://stackoverflow.com/questions/11716687/why-does-str-split-not-take-keyword-arguments) – Mikel Jul 17 '14 at 15:47
  • Thanks for the links. Geeze, what a mess :( – wim Jul 17 '14 at 15:54

1 Answers1

0

If the documentation doesn't specifically describe an argument as being a named argument than you shouldn't assume that it has a name. This is true even when in fact does does have a name (eg. most functions defined in Python code), because unless the documentation describes it as being a named argument no promises have been made. The implementation is free to change the name or require that it be passed as a positional argument.

That said, in many cases the documentation is deficient and won't describe an argument as being named when it intends or even requires it to be passed as a named argument. Those cases will indeed require familiarity with the language in order to read between the lines and figure out what you should be doing.

btw. You're not creating a baseless class by passing () as the base. type will make object the base, as all new style classes are derived from object. You can't make a baseless old-style class this way.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
  • I have seen people explicitly passing `(object,)` as the bases before, are you saying this is redundant in python2? My example code was in python3, by the way, when there is no such thing as old-style class.. – wim Jul 17 '14 at 16:22
  • I wouldn't say redundant so much as explicit. The documentation for `type` doesn't actually say what happens when you pass an empty tuple. – Ross Ridge Jul 17 '14 at 16:28