Order of using positional and keyword arguments - python-3.x

Apparently, if you need to use both keyword and positional arguments while calling your function, you have to use the positional argument first. But the following code results in an error;
def greet(first_name, l_name):
print(f'Hi, {first_name} {last_name}!')
greet('Holmes',
first_name='Harry')
So does it mean that if you're using both, you have to use the positional argument first in the required order, and only then the keyword argument?

Positional arguments must be passed in order as declared in the function. So if you pass three positional arguments, they must go to the first three arguments of the function, and those three arguments can't be passed by keyword. If you want to be able to pass the first argument out of order by keyword, all your arguments must be passed by keyword (or not at all, if they have defaults).
If it helps, Python's binding mechanism is roughly:
Assign positional arguments one by one to sequential parameters of the function. These parameters are now set.
Assign keyword arguments to remaining parameters in any order. If one of the keyword arguments matches an argument already assigned positionally (or the same keyword argument is passed twice), it's an error.
In your case, what this means is that:
greet('Holmes', first_name='Harry')
first binds 'Holmes' to first_name. Then it saw you tried to pass first_name again as a keyword argument and objected.

Related

What would be the possible causes for the type error: function () got multiple values for keyword argument?

I wanted to use keyword argument instead of positional argument. However, it repeatedly displays the following type error: function () got multiple values for the argument.
I tried to verify the code using a positional argument and removing the space after the comma that separates the two arguments with the expectation of solved error. Nevertheless, the same repeated message appeared actually.

Update-MgDevice - issue with changing accountEnabled status [duplicate]

I'm struggling to understand the outputs of the below function
function testApp
{
param(
[string] $appName,
[switch] $sw = $false,
[string[]] $test,
[string[]] $test2
)
Write-Host $appName - $sw - $test - $test2
}
testApp -appName "TestApp" -sw $true -test "one", "two" -test2 "three","four"
Output: TestApp - True - one two - three four
testApp -appName "TestApp" -sw $true -test "one", "two"
Output: TestApp - True - one two - True
The first output is as expected. But I cannot understand why the second output has "True" for the test2 array when I did not pass it. Can anyone help me in understanding the reason for the behavior? Thanks.
To summarize and complement the helpful comments on the question by Lee_Dailey, Matthew and mclayton:
[switch] parameters in PowerShell (aka flags in other shells):
switch parameters are meant to imply $true vs. $false by their presence in an invocation: e.g., passing -sw by itself signals $true, whereas omitting -sw signals $false.
It is possible to pass a Boolean value explicitly, for the purpose of passing a programmatically determined value; e.g.: -sw:$var
Note the required : following the switch name, which tells PowerShell that the Boolean value belongs to the switch parameter; without it, PowerShell thinks the value is a positional argument meant for a different parameter (see below).
Caveat: Commands may interpret -sw:$false differently from omitting -sw; a prominent example is is the use of common parameter -Confirm:$false to override the effective $ConfirmPreference value.
If you need to make this distinction in your own code, use $PSBoundParameters.ContainsKey('sw') -and -not $sw to detect the -sw:$false case.
Do not assign a default value to a switch parameter variable: while technically possible, the convention is that switches default to $false (which is a [switch] instance's default value anyway); that is, a [switch] parameter should always have opt-in logic.
A [switch] parameter variable effectively behaves like a Boolean value in most contexts:
That is, you can say if ($sw) { ... }, for instance.
If you need to access the wrapped Boolean value explicitly, access the .IsPresent property (note that the property name is somewhat confusing, because in a -sw:$false invocation the switch is still present, but its value, as reflected in .IsPresent, is $false).
An example of where .IsPresent is needed is the use of a Boolean as an implicit array index, notably to emulate a ternary conditional[1]: ('falseValue', 'trueValue')[$sw.IsPresent]; without the .IsPresent, the effective Boolean value wouldn't be recognized as such and wouldn't automatically be mapped to index 0 (from $false) or 1 (from $true).
Ultimately, your problem was that you thought $true was an argument for -sw, whereas it became a positional argument implicitly bound to the -test2 parameter.
[switch] parameters never need a value, so the next argument becomes a separate, positional argument - unless you explicitly indicate that the argument belongs to the switch by following the switch name with :, as shown above.[2]
Positional vs. named argument passing in PowerShell:
Terminology note: For conceptual clarity the term argument is used to refer to a value passed to a declared parameter. This avoids the ambiguity of using parameter situationally to either refer to the language construct that receives a value vs. a given value.
Named argument passing (binding) refers to explicitly placing the target parameter name before the argument (typically separated by a space, but alternatively also and / or by :); e.g., -AppName foo.
The order in which named arguments are passed never matters.
Positional (unnamed) argument passing refers to passing an argument without preceding it by the name of its target parameter; e.g., foo.
The passing is positional in the sense that the relative position (order) among other unnamed arguments determines what target parameter is implied.
[switch] parameters are the exception in that they:
are typically passed by name only (-sw), implying value $true, and if a value is passed, require : to separate the name from the value.
never support positional binding.
You may combine named passing with positional passing, in which case the named arguments are bound first, after which the positional ones are then considered (in order) for binding to the not-yet-bound parameters.
PowerShell functions are simple functions by default. In order to exercise control over positional binding, use of the [CmdletBinding()] and / or [Parameter()] attributes is necessary (see below), which invariably turn a simple function into an advanced function.
Making a simple function an advanced one has larger behavioral implications (mostly beneficial ones), which are detailed in this answer.
By default, PowerShell functions accept positional arguments for any parameter (other than those of type [switch]), in the order in which the parameters were declared.
Additionally, simple functions accept arbitrary additional arguments for which no parameters were declared, which are collected in the automatic $args array variable.
To prevent your function from accepting any positional arguments by default, place a [CmdletBinding(PositionalBinding=$false, ...)] attribute above the param(...) block.
Since this makes your function an advanced one, this also disables passing arbitrary additional arguments ($args no longer applies and isn't populated).
As an aside: when you implement a cmdlet (a command implemented as a binary, typically via C#), this behavior is implied.
To selectively support positional arguments, decorate individual parameter declarations with a [Parameter(Position=<n>, ...)] attribute (e.g, [Parameter(Position=0)] [string] $Path)
Note: Whether you start your numbering with 0 or 1 doesn't matter, as long as the numbers used reflect the desired ordering among all positional parameters; 0 is advisable as a self-documenting convention, because it is unambiguous.
Attribute [Parameter(Position=<n>)] is an explicit opt-in that selectively overrides [CmdletBinding(PositionalBinding=$false)]: that is, the latter disables positional binding unless explicitly indicated by individual parameter declarations; in fact, the latter is implied by the former, in that once you use one [Parameter(Position=<n>)] attribute, you must use it on all other parameters you want to bind positionally as well.
[1] Note that PowerShell [Core] 7.0+ supports ternary conditionals natively: $sw ? 'trueValue' : 'falseValue'
[2] In effect, [switch] parameters are the only type for which PowerShell supports an optional argument. See this answer for more information.

Passing one list instead of two in python

Here I have written a function which takes two lists as argument. But when I called this function passing one list as argument, it works well! Why is this working? Here name_function has two arguments but I passed only one list as argument.
def name_function(names=list(),_list=list()):
for name in names:
_list.append(name)
return _list
print(name_function(['mike','smith','bob']))
Here in the function definition you have initialized both the
arguments with the empty list i.e. you are using two default
arguments in the function definition.
For the above reason the function call works if you provide provide
both the arguments or any one of the arguments or no argument at
all.
To learn more about default arguments in python you can refer this
link or this link.

Best Way to Pass Arguments from One Function to Another in Python

I have a function that performs a specific task, and this function takes many options, both named and unnamed options. For example:
def eat_fruit(x,a_number=None , a_fruit=None):
return(f'{x} ate {str(a_number)} {a_fruit}')
#call the function
eat_fruit("John",a_number=5,a_fruit='apples') #outputs 'John ate 5 apples'
Now, I have another function that takes many options, for example:
def do_lots_of_stuff(a,b,activity_1=None,activity_2=None):
return(f'''{a} and {b} {activity_1} and {activity_2}''')
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump') #returns "Bob and Mary run and jump"
I want to have the function do_lots_of_stuff call the function eat_fruit, sometimes with options. However, it is not clear to me how to pass options from one to the other in a straightforward manner.
Ideally, I am looking for something like:
#This code does not work; it demos the type of functionality I am looking for.
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump', eat_fruit_options={*put_options_here*}):
eat_fruit(eat_fruit_options)
return(f'''{a} and {b} {activity_1} and {activity_2}''')
Note that this can't be accomplished via do_lots_of_stuff(*do_lots_of_stuff_options*, *eat_fruit_options*) since options for eat_fruit are not valid do_lots_of_stuff options. Furthermore, keyword arguments must come after positional arguments. In addition this solution does not seem to be sufficient here, because I only want to pass some arguments, not all of them.
Other relevant links (although I don't believe they successfully address my question):
can I pass all positional arguments from one function to another in python?
Passing variables between functions in Python
Passing value from one function to another in Python
do_lots_of_stuff("Bob","Mary",activity_1='run',activity_2='jump', eat_fruit_args=["John"], eat_fruit_kwargs={"a_number": 5, "a_fruit": "apples"}):
eat_fruit(*eat_fruit_args, **eat_fruit_kwargs)
return(f'''{a} and {b} {activity_1} and {activity_2}''')
You can pass and forward arguments and keyword arguments. Arguments are in the form of a list. Keyword arguments (kwargs) are in the form of a dictionary, with the key as a string, and the value as the correlating keyword value.

Lambda commands for tracing tkinter variables [duplicate]

Python has classes for Tkinter variables StringVar(), BooleanVar(), etc. These all share the methods get(), set(string), and trace(mode, callback). The callback function passed as the second argument to trace(mode, callback) is passed four arguments, self, n, m, x.
For an example of a BooleanVar() these appear to be '', 'PYVAR0', 'w'.
The third argument x appears to be the mode that triggered the trace, in my case the variable was changed. However, what is the first variable that appears to be an empty string? What is the second, if I had to guess I'd say some internal name for the variable?
The first argument is the internal variable name. You can use this name as an argument to the tkinter getvar and setvar methods. If you give your variable a name (eg: StringVar(name='foo')) this will be the given name, otherwise it will be a name generated for you by tkinter (eg: PYVAR0)
If the first argument represents a list variable (highly unlikely in tkinter), the second argument will be an index into that list. If it is a scalar variable, the second argument will be the empty string.
The third argument is the operation, useful if you are using the same method for reading, writing and/or deleting the variable. This argument tells you which operation triggered the callback. It will be one of "read", "write", or "unset".
Tkinter is a python wrapper around a tcl/tk interpreter. The definitive documentation for variable traces can be found here: http://tcl.tk/man/tcl8.5/TclCmd/trace.htm#M14. Though, this only documents how the internal trace works, the tkinter wrapper sometimes massages the data.
The first argument is the name of the variable, but is not "useless" since you can set it when you declare the variable, e.g.:
someVar = IntVar(name="Name of someVar")
When you check the first argument in the trace callback it will equal "Name of someVar". Using the name to distinguish between variables, you can then bind the same handler to trace changes to any number of variables, rather than needing a separate handler for each variable.

Resources