We say an object is "callable" if it "has a mouth" meaning it makes sense to put parentheses after it.
Object( ) "has a mouth" in that "( )" looks like "lips" 💋 turned sideways, as in the old sideways emoticons, such as ;-() instead of a "winking face" 😉 emoji.
Careful though: putting parentheses after an object may also be a harmless use of syntax that doesn't end up triggering an object's __call__
method -- because maybe it doesn't have one!
For example you may write:
if(1 != 2):
print("OK then")
The parens after the if
are harmless. But they make it look as if the keyword if
might be callable. It isn't (in Python that is). if
is a Python keyword and none of the keywords are callable.
The better more stylish way to write the above is:
if 1 != 2:
print("OK then")
or even:
if (1 != 2):
print("OK then")
The single space after if
proves you know you're not "calling" if
(even though, if if were callable, that space would not matter, i.e. if
would be called). Confused yet?
Just remember: no Python keyword is callable. And what are the keywords again?
import keyword
print(keyword.kwlist)
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
Likewise, if this were Python 2.7, the print
statement followed by a string in parentheses would still work, even though print
is not actually being called.
Both of these work in Python 2.x:
print "OK then" # better in 2.x
print("OK then") # harmless parens
In Python 3.x, on the other hand, print is most definitely a callable. print
is now a function, not a keyword. Parens are mandatory plus you now have a few optional named arguments such as sep=, end= and file=.
callable(print)
True
import sys
print(sys.version)
3.7.9 (default, Aug 31 2020, 07:22:35) [Clang 10.0.0 ]
print("Hello", "there", sep="_", end="!\n")
Hello_there!
Once you have determined an object is callable, the next question is does it take arguments. Not all callables do, though they do require the parens anyway.
A related question would be: how do I define my own callables, including specifying its arguments.
Technically speaking, we may want to distinguish parameters from arguments. What you pass to a callable at runtime are arguments. What they match up with, are parameters defined at design time.
def function_0(a, b): # two positional arguments
pass
def function_1(a, b=0): # one positional, one named
pass
def function_2(a=0, b=1): # two named arguments
pass
# no errors
function_0(1, 2)
function_1(1)
function_2()
Above you'll see three functions having their parameters defined at design time. Parameters come in two basic flavors: positional and named. Named arguments are also sometimes called keyword arguments, not to be confused with Python keywords.
Then each of the functions gets called, with as few arguments as necessary. Named arguments supply default values, which may be overridden, or left alone.
Think of the callable's "mouth" or intake, expecting arguments in a certain order, and/or with specific names.
How Python matches arguments, to parameters set up to receive them, should be an unambiguous. And it is. But it's also somewhat of a long story. Many rules apply, consistently with one another.
For example, named arguments should have only one target parameter, or Python will raise a SyntaxError.
No good:
def bad_form(a, a=10):
pass
bad_form(a = 11) # would leave Python guessing.
def any_function(x, y, z, a=1, b=2):
pass
Given the above design time definition, all of these functions calls would be valid at runtime:
any_function(1,2,3,4,5) # reach all five positionally
any_function(b=1, a=2, x=3, y=2, z=1) # match by name
any_function(1,2,3) # named parameters don't need args
Wouldn't it be lovely if parameters could be defined in a more open-ended manner, such that any number of positional and/or named arguments might be passed, and get matched up with something.
That's exactly what the star and double-star operators are for. Used with parameters, they allow for positionals and named arguments to get collected into a tuple and dictionary respectively.
def function_3(a, *b): # at least one positional, scoop to tuple
print("a:", a, "b:", b)
def function_4(a, **b): # one positional or a= + any named args
print("a:", a, "b:", b)
def function_5(a, *, b): # a might be name, b must be named
print("a:", a, "b:", b)
function_3(1) # b left empty
a: 1 b: ()
function_3(1, 2, 3, 4, 5, 6)
a: 1 b: (2, 3, 4, 5, 6)
function_4(a=1, r=2, s=3, t=4) # naming a positional is OK
a: 1 b: {'r': 2, 's': 3, 't': 4}
function_4(1, r=2, s=3, t=4)
a: 1 b: {'r': 2, 's': 3, 't': 4}
function_5(1, b=2) # b must be named
a: 1 b: 2
function_5(a=1, b=2) # a might be
a: 1 b: 2
# Python 3.9 and above
#def function_6(a, b, /, c):
# pass
Above, positionals to the left of the slash may not be referred to by name, whereas positionals to the right still might be.
# function_6(1,2,c=3)
Below, two and only two inputs may be given.
def average(a, b):
return (a + b)/2
average(10, 20)
15.0
Now with a star prefix, args will be a tuple containing as many arguments as were positionally passed in.
def average(*args): # * makes args a scooper
print(args) # scooped to tuple
return sum(args)/len(args)
average(10, 20, 15, 6, 7, 14, 5, -6)
(10, 20, 15, 6, 7, 14, 5, -6)
8.875
shapes = {"tetrahedron": 1, "cube": 3, "octahedron": 4}
{**shapes} # unpacking a dict and repacking
{'tetrahedron': 1, 'cube': 3, 'octahedron': 4}
dict(shapes.items()) # dict eats tuple of tuples
{'tetrahedron': 1, 'cube': 3, 'octahedron': 4}
dict(**shapes) # dict eats named arguments
{'tetrahedron': 1, 'cube': 3, 'octahedron': 4}
The format method of the string type serves as an intake for positional and/or named arguments. If you have a dict, and want to turn it into named arguments, you're in luck, thanks to the double-star unpacking operator.
print("""\
POLYHEDRON VOLUMES
Tetrahedron: {tetrahedron}
Cube: {cube}
Octahedron: {octahedron}
""".format(**shapes)
)
POLYHEDRON VOLUMES Tetrahedron: 1 Cube: 3 Octahedron: 4