Bare asterisk in function arguments?
Bare *
is used to force the caller to use named arguments - so you cannot define a function with *
as an argument when you have no following keyword arguments.
See this answer or Python 3 documentation for more details.
What is the purpose of a bare asterisk in function arguments?
PEP 3102 explains the rationale pretty clearly: the point is to allow functions to accept various "options" that are essentially orthogonal in nature. Specifying these positionally is awkward both on the defining and calling side, since they don't have any obvious "priority" that would translate into a positional order.
There are lots of example of functions that would benefit from this in various libraries. For instance, the call signature of pandas.read_csv
is:
def parser_f(filepath_or_buffer,
sep=sep,
dialect=None,
compression=None,
doublequote=True,
escapechar=None,
quotechar='"',
quoting=csv.QUOTE_MINIMAL,
skipinitialspace=False,
lineterminator=None,
header='infer',
index_col=None,
names=None,
prefix=None,
skiprows=None,
skipfooter=None,
skip_footer=0,
na_values=None,
na_fvalues=None,
true_values=None,
false_values=None,
delimiter=None,
converters=None,
dtype=None,
usecols=None,
engine='c',
delim_whitespace=False,
as_recarray=False,
na_filter=True,
compact_ints=False,
use_unsigned=False,
low_memory=_c_parser_defaults['low_memory'],
buffer_lines=None,
warn_bad_lines=True,
error_bad_lines=True,
keep_default_na=True,
thousands=None,
comment=None,
decimal=b'.',
parse_dates=False,
keep_date_col=False,
dayfirst=False,
date_parser=None,
memory_map=False,
nrows=None,
iterator=False,
chunksize=None,
verbose=False,
encoding=None,
squeeze=False,
mangle_dupe_cols=True,
tupleize_cols=False,
infer_datetime_format=False):
Except for the filepath, most of these are orthogonal options that specify different aspects of how a CSV file is to be parsed. There's no particular reason why they would be passed in any particular order. You'd go nuts keeping track of any positional order for these. It makes more sense to pass them as keywords.
Now, you can see that pandas doesn't actually define them as keyword-only arguments, presumably to maintain compatibility with Python 2. I would imagine that many libraries have refrained from using the syntax for the same reason. I don't know offhand which libraries (if any) have started using it.
Python method/function arguments starting with asterisk and dual asterisk
The *args
and **keywordargs
forms are used for passing lists of arguments and dictionaries of arguments, respectively. So if I had a function like this:
def printlist(*args):
for x in args:
print(x)
I could call it like this:
printlist(1, 2, 3, 4, 5) # or as many more arguments as I'd like
For this
def printdict(**kwargs):
print(repr(kwargs))
printdict(john=10, jill=12, david=15)
*args
behaves like a list, and **keywordargs
behaves like a dictionary, but you don't have to explicitly pass a list
or a dict
to the function.
See this for more examples.
What does the asterisk * mean as the first argument in the signature of a function/class/method?
Any arguments specified after the *
"argument" (so in this case, all of them) are keyword-only arguments. They can only be supplied by keyword, rather than positionally; this means your example should be:
from tensorforce.core.layers import Dense
d = Dense(size=4)
That error message you got is not terribly intuitive, is it? This is a consequence of the fact that in Python, an object's method is essentially a function that automatically receives the object itself as the first argument (which is why you normally write self
in a method definition, but don't supply it when calling the method).
In this case, the __init__
method takes one and exactly one positional argument: its own object instance. Since you also provided size
positionally, Python complains that it got two arguments—even though you only explicitly gave it one.
What do * (single star) and / (slash) do as independent parameters?
There is a new function parameter syntax /
to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments.[This is new in Python 3.8
]
Documentation specifies some of the use cases/benefits of positional-only parameters
It allows pure Python functions to fully emulate behaviors of
existing C coded functions. For example, the built-inpow()
function does not accept keyword arguments:def pow(x, y, z=None, /):
"Emulate the built in pow() function"
r = x ** y
return r if z is None else r%zAnother use case is to preclude keyword arguments when the parameter
name is not helpful. For example, the builtinlen()
function has
the signaturelen(obj, /)
. This precludes awkward calls such as:len(obj='hello') # The "obj" keyword argument impairs readability
A further benefit of marking a parameter as positional-only is that
it allows the parameter name to be changed in the future without
risk of breaking client code. For example, in the statistics module,
the parameter name dist may be changed in the future. This was made
possible with the following function specification:def quantiles(dist, /, *, n=4, method='exclusive')
...
Where as *
is used to force the caller to use named arguments. This is one of the use case of named arguments.
So, given the method,
def func(self, param1, param2, /, param3, *, param4, param5):
print(param1, param2, param3, param4, param5)
It must called with
obj.func(10, 20, 30, param4=50, param5=60)
or
obj.func(10, 20, param3=30, param4=50, param5=60)
ie,
param1
,param2
must be specified positionally.param3
can be called either with positional or keyword.param4
andparam5
must be called with keyword argument.
DEMO:
>>> class MyClass(object):
... def func(self, param1, param2, /, param3, *, param4, param5):
... return param1, param2, param3, param4, param5
...
>>> obj = MyClass()
>>>
>>> assert obj.func(10, 20, 30, param4=40, param5=50), obj.func(
... 10, 20, param3=30, param4=40, param5=50
... )
What does asterisk * mean in Python?
See Function Definitions in the Language Reference.
If the form
*identifier
is
present, it is initialized to a tuple
receiving any excess positional
parameters, defaulting to the empty
tuple. If the form**identifier
is
present, it is initialized to a new
dictionary receiving any excess
keyword arguments, defaulting to a new
empty dictionary.
Also, see Function Calls.
Assuming that one knows what positional and keyword arguments are, here are some examples:
Example 1:
# Excess keyword argument (python 2) example:
def foo(a, b, c, **args):
print "a = %s" % (a,)
print "b = %s" % (b,)
print "c = %s" % (c,)
print args
foo(a="testa", d="excess", c="testc", b="testb", k="another_excess")
As you can see in the above example, we only have parameters a, b, c
in the signature of the foo
function. Since d
and k
are not present, they are put into the args dictionary. The output of the program is:
a = testa
b = testb
c = testc
{'k': 'another_excess', 'd': 'excess'}
Example 2:
# Excess positional argument (python 2) example:
def foo(a, b, c, *args):
print "a = %s" % (a,)
print "b = %s" % (b,)
print "c = %s" % (c,)
print args
foo("testa", "testb", "testc", "excess", "another_excess")
Here, since we're testing positional arguments, the excess ones have to be on the end, and *args
packs them into a tuple, so the output of this program is:
a = testa
b = testb
c = testc
('excess', 'another_excess')
You can also unpack a dictionary or a tuple into arguments of a function:
def foo(a,b,c,**args):
print "a=%s" % (a,)
print "b=%s" % (b,)
print "c=%s" % (c,)
print "args=%s" % (args,)
argdict = dict(a="testa", b="testb", c="testc", excessarg="string")
foo(**argdict)
Prints:
a=testa
b=testb
c=testc
args={'excessarg': 'string'}
And
def foo(a,b,c,*args):
print "a=%s" % (a,)
print "b=%s" % (b,)
print "c=%s" % (c,)
print "args=%s" % (args,)
argtuple = ("testa","testb","testc","excess")
foo(*argtuple)
Prints:
a=testa
b=testb
c=testc
args=('excess',)
Related Topics
How to Save/Restore a Model After Training
Convert Hex String to Integer in Python
"Pip Install Unroll": "Python Setup.Py Egg_Info" Failed With Error Code 1
Can't Modify List Elements in a Loop
Multiple Assignment and Evaluation Order in Python
Filter Dataframe Rows If Value in Column Is in a Set List of Values
Does Python Optimize Tail Recursion
Text Progress Bar in Terminal With Block Characters
How to Install Pip on Macos or Os X
Why Is _Init_() Always Called After _New_()
How to Call a Function Within a Class
How to Create a Text Input Box With Pygame
Word Boundary With Words Starting or Ending With Special Characters Gives Unexpected Results