The decision of whether to use a method is not up to the API user, it is
up to the API designer, who should have a good idea of the range of
You are concerned about the users being able to “quickly determine if
parentheses should be added or not”, but I think you are making a
mountain out of a mole-hill:
If the user is familiar with the API, they will know from experience.
If they are not familiar, they will have to look it up anyway, to find
out what API they need to call. Is it str.upper or .uppercase or Upper
or convert_to_UPPER or something else? That will tell them whether it is
a method that needs parentheses or not.
If they are using an IDE or editor with code auto-completion, the
editor will add the parentheses for them.
Getting help is only a few key strokes away if you have a Python
interactive iterpreter open, which you should have:
<built-in method upper of str object at 0x7f8cbea663b0>
Now I know I need parentheses.
Everything is hard if you are not familiar with the API:
widget.mogrify(a, b) or
mogrified(widget, a, b) or
widget.mogrified(b, a) or something else? Worrying especially about
the need for parentheses or not is unnecessary.
“make all methods that have zero arguments and will never have arguments
look like an attribute (without parentheses)”
Things that look like attributes imply that:
(1) They are cheap. I don’t need to save the result for re-use.
for paragraph in document:
para = format(paragraph, page.width)
That’s great, unless calculating the page width is slow, then your whole
program is slow.
(2) It also implies that I can set the attribute:
page.width = 500
If that was written
page.width() I would know not even to try.
(3) Attributes should be things, not actions. A zero-argument method
is still an action, and should have parentheses:
# Yes, methods are actions.
# No, looking up an attribute should not have side-effects.
# Actions should be methods, not attributes.
“make everything that returns a value have parentheses.”
That’s were we get Java getters and setters. They are horrible:
sys.ps1 = '>>> '
# Java-style getters and setters
“Of these I currently tend towards the first solution: why would we
actually need parentheses anyways?”
Because referring to a function or method is not the same as calling
that function or method.
If callables automatically got called without parentheses, you couldn’t
because the reference to float would automatically call it and give you
0.0, and you can’t call isinstance(value, 0.0).
You couldn’t pass functions or methods as key functions:
# would automatically call str.upper and raise an exception
or as callback functions. Dependency injection would be horrible:
# Easy in Python
def myfunction(arg, randomness=random.random):
value = myfunction(20) # Use the default source of randomness.
value = myfunction(20, myrandomness) # Inject the dependency.
Functional programming techniques would be horrible:
map(func, values) # would automatically call func and fail
It would make testing harder:
# This would fail:
for func in [str.lower, str.upper, str.index, str.find]:
test(func, value, expected)
Methods and functions are objects. Grabbing a reference to them is not
the same as calling them.
Ruby allows you to leave out parentheses when calling zero argument
functions, and it is a real pain. It means that things which are
trivially easy in Python are hard and annoying in Ruby.