What does *[, keyword_arg = value] do in Python keyword only function definition? - python-3.x

Consider this:
help(min)
which gives:
Help on built-in function min in module builtins:
min(...)
min(iterable, *[, default=obj, key=func]) -> value
min(arg1, arg2, *args, *[, key=func]) -> value
With a single iterable argument, return its smallest item. The
default keyword-only argument specifies an object to return if
the provided iterable is empty.
With two or more arguments, return the smallest argument.
My question is what is the difference between:
min(iterable, *[, default=obj, key=func]) -> value
and
min(iterable, *, default=obj, key=func) -> value

The Python documentation/help derives from EBNF to describe grammar. A pair of [ ] means "optional" in EBNF and the Python documentation; for terseness, common symbols like ( ) and names are not quoted in the documentation even though this has different meaning in EBNF.
The * and , are derived from Python's call syntax. * means "end of positional parameters".
For the concrete example of
min(iterable, *[, default=obj, key=func]) -> value
this means default and key are optional keyword-only parameters.

This is not Python syntax, it is just used in the help text to show that those arguments are optional.

Related

element => command in Terraform

I see a code as below in https://github.com/terraform-aws-modules/terraform-aws-efs/blob/master/examples/complete/main.tf#L58
# Mount targets / security group
mount_targets = { for k, v in toset(range(length(local.azs))) :
element(local.azs, k) => { subnet_id = element(module.vpc.private_subnets, k) }
}
I am trying to understand what => means here. Also this command with for loop, element and =>.
Could anyone explain here please?
In this case the => symbol isn't an independent language feature but is instead just one part of the for expression syntax when the result will be a mapping.
A for expression which produces a sequence (a tuple, to be specific) has the following general shape:
[
for KEY_SYMBOL, VALUE_SYMBOL in SOURCE_COLLECTION : RESULT
if CONDITION
]
(The KEY_SYMBOL, portion and the if CONDITION portion are both optional.)
The result is a sequence of values that resulted from evaluating RESULT (an expression) for each element of SOURCE_COLLECTION for which CONDITION (another expression) evaluated to true.
When the result is a sequence we only need to specify one result expression, but when the result is a mapping (specifically an object) we need to specify both the keys and the values, and so the mapping form has that additional portion including the => symbol you're asking about:
{
for KEY_SYMBOL, VALUE_SYMBOL in SOURCE_COLLECTION : KEY_RESULT => VALUE_RESULT
if CONDITION
}
The principle is the same here except that for each source element Terraform will evaluate both KEY_RESULT and VALUE_RESULT in order to produce a key/value pair to insert into the resulting mapping.
The => marker here is just some punctuation so that Terraform can unambiguously recognize where the KEY_RESULT ends and where the VALUE_RESULT begins. It has no special meaning aside from being a delimiter inside a mapping-result for expression. You could think of it as serving a similar purpose as the comma between KEY_SYMBOL and VALUE_SYMBOL; it has no meaning of its own, and is only there to mark the boundary between two clauses of the overall expression.
When I read a for expression out loud, I typically pronounce => as "maps to". So with my example above, I might pronounce it as "for each key and value in source collection, key result maps to value result if the condition is true".
Lambda expressions use the operator symbol =, which reads as "goes to." Input parameters are specified on the operator's left side, and statement/expressions are specified on the right. Generally, lambda expressions are not directly used in query syntax but are often used in method calls. Query expressions may contain method calls.
Lambda expression syntax features are as follows:
It is a function without a name.
There are no modifiers, such as overloads and overrides.
The body of the function should contain an expression, rather than a statement.
May contain a call to a function procedure but cannot contain a call to a subprocedure.
The return statement does not exist.
The value returned by the function is only the value of the expression contained in the function body.
The End function statement does not exist.
The parameters must have specified data types or be inferred.
Does not allow generic parameters.
Does not allow optional and ParamArray parameters.
Lambda expressions provide shorthand for the compiler, allowing it to emit methods assigned to delegates.
The compiler performs automatic type inference on the lambda arguments, which is a key advantage.

Reading class method definition - what is Callable?

I am relatively new to python, and I started to read the docs when using packages, but I'm having a hard time understanding some of it:
post_to_main_thread(self: open3d.cpu.pybind.visualization.gui.Application, arg0: open3d::visualization::gui::Window, arg1: Callable[[], None]) → None
the only thing here that I don't understand is the arg1 with that callable, and I can't find an explanation on it at the web.
Interesting question!
So post_to_main_thread() is a method that takes 3 arguments (inputs/variables) and returns None.
Because it's a method (a function associated with a class, not just a standalone function) the first argument, self, refers to the instance of the class that the function is part of.
The other two arguments are passed within the function parentheses, as expected with a standalone function. So a call might look like this:
instance_name = open3d.visualization.gui.Application(...)
instance_name.post_to_main_thread(arg1, arg2)
arg1 should be of type open3d::visualization::gui::Window. This is an instance of the class open3d.visualization.gui.Window().
arg2 should be of type Callable(). This describes a number of built-ins that you can find details about in the documentation. To quote:
The subscription syntax must always be used with exactly two values: the argument list and the return type. The argument list must be a list of types or an ellipsis; the return type must be a single type.
So in this case the type should be Callable[[], None], which means this should be a function that takes no input and returns None. Carrying on from our previous example, you'd pass this as an argument like so:
def my_callable:
print('Hello, World!')
return
instance_name.post_to_main_thread(arg1, my_callable)
Does that clear things up?

Why does Python `f-string` + inline for loop create a generator when they're passed as parameter?

I found this example on the internet
def format_attributes(**attributes):
"""Return a string of comma-separated key-value pairs."""
return ", ".join(
f"{param}: {value}"
for param, value in attributes.items()
)
The syntax of the param passed to the join function caught my attention because it's sort of unusual. But it works
Doing some local testing with a minimum codebase I discovered that in:
def foo(res):
return res
print(foo(f"{s}" for s in ["bar"]))
foo's syntax is valid and res ends up being a generator. However, if I try f"{s}" for s in ["bar"] standalone (no function in between), the expression just throws a SyntaxError: invalid syntax.
How come the f-string + for loop is valid and gets converted into a generator? What's happening under the hood when invoking foo function?
These other questions uses the same syntax:
f-strings formatter including for-loop or if conditions
https://stackoverflow.com/a/54734702/5745962
But I found no comment explaining why this happens
The looping construct you're using is a generator expression. To write one as a stand-alone expression, you need to add parentheses around it:
genexp = (f"{s}" for s in ["bar"])
If the generator expression is the only argument to a function, you don't need double parentheses (but you do if there are other separate arguments). Contrast:
s = sum(i % 2 for i in some_sequence) # count of odd elements, no extra parentheses needed
vs:
print(*(i for i in some_sequence if i % 2), sep=",") # print odds, parens are needed this time
There's nothing special about f-string used in the generator expression in your code, any expression works the same way.
These are examples of generator expressions and don't necessarily have anything specific to f-strings or which functions you use with them.
e.g.
>>> x = [1, 2, 3, 4]
>>> sum(i%2==0 for i in x)
2
The example counts the number of even integers in the list.
You can read more about them here: https://dbader.org/blog/python-generator-expressions
The f-string has nothing to do with it.
Although a generator expression generally requires parentheses:
some_gen = (f"{s}" for s in ["bar"])
print(foo(some_gen))
the parentheses can be omitted when the generator expression is the only argument to a function call:
# These two calls are equivalent.
foo((f"{s}" for s in ["bar"]))
foo( f"{s}" for s in ["bar"] )

python: What does / and * mean in the python documentation? [duplicate]

What does the / mean in Python 3.4's help output for range before the closing parenthesis?
>>> help(range)
Help on class range in module builtins:
class range(object)
| range(stop) -> range object
| range(start, stop[, step]) -> range object
|
| Return a virtual sequence of numbers from start to stop by step.
|
| Methods defined here:
|
| __contains__(self, key, /)
| Return key in self.
|
| __eq__(self, value, /)
| Return self==value.
...
It signifies the end of the positional only parameters, parameters you cannot use as keyword parameters. Before Python 3.8, such parameters could only be specified in the C API.
It means the key argument to __contains__ can only be passed in by position (range(5).__contains__(3)), not as a keyword argument (range(5).__contains__(key=3)), something you can do with positional arguments in pure-python functions.
Also see the Argument Clinic documentation:
To mark all parameters as positional-only in Argument Clinic, add a / on a line by itself after the last parameter, indented the same as the parameter lines.
and the (very recent addition to) the Python FAQ:
A slash in the argument list of a function denotes that the parameters prior to it are positional-only. Positional-only parameters are the ones without an externally-usable name. Upon calling a function that accepts positional-only parameters, arguments are mapped to parameters based solely on their position.
The syntax is now part of the Python language specification, as of version 3.8, see PEP 570 – Python Positional-Only Parameters. Before PEP 570, the syntax was already reserved for possible future inclusion in Python, see PEP 457 - Syntax For Positional-Only Parameters.
Positional-only parameters can lead to cleaner and clearer APIs, make pure-Python implementations of otherwise C-only modules more consistent and easier to maintain, and because positional-only parameters require very little processing, they lead to faster Python code.
I asked this question myself. :) Found out that / was originally proposed by Guido in here.
Alternative proposal: how about using '/' ? It's kind of the opposite
of '*' which means "keyword argument", and '/' is not a new character.
Then his proposal won.
Heh. If that's true, my '/' proposal wins:
def foo(pos_only, /, pos_or_kw, *, kw_only): ...
I think the very relevant document covering this is PEP 570.
Where recap section looks nice.
Recap
The use case will determine which parameters to use in the function definition:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
As guidance:
Use positional-only if names do not matter or have no meaning, and there are only a few arguments which will always be passed in the same order.
Use keyword-only when names have meaning and the function definition is more understandable by being explicit with names.
If the function ends with /
def foo(p1, p2, /)
This means all functional arguments are positional.
Forward Slash (/) indicates all arguments prior to it are positional only argument. Positional only arguments feature was added in python 3.8 after PEP 570 was accepted. Initially this notation was defined in PEP 457 - Notation for Notation For Positional-Only Parameters
Parameters in function definition prior Foraward slash (/) are positional only and parameters followed by slash(/) can be of any kind as per syntax. Where arguments are mapped to positional only parameters solely based on their position upon calling a function. Passing positional-only parameters by keywords(name) is invalid.
Let's take following example
def foo(a, b, / , x, y):
print("positional ", a, b)
print("positional or keyword", x, y)
Here in the above function definition parameters a and b are positional-only, while x or y can be either positional or keyword.
Following function calls are valid
foo(40, 20, 99, 39)
foo(40, 3.14, "hello", y="world")
foo(1.45, 3.14, x="hello", y="world")
But, following function call is not valid which raises an exception TypeError since a, b are not passed as positional arguments instead passed as keyword
foo(a=1.45, b=3.14, x=1, y=4)
TypeError: foo() got some positional-only arguments passed as keyword
arguments: 'a, b'
Many built in function in python accept positional only arguments where passing arguments by keyword doesn't make sense. For example built-in function len accepts only one positional(only) argument, Where calling len as len(obj="hello world") impairs readability, check help(len).
>>> help(len)
Help on built-in function len in module builtins:
len(obj, /)
Return the number of items in a container.
Positional only parameters make underlying c/library functions easy to maintain. It allows parameters names of positional only parameters to be changes in future without risk of breaking client code that uses API
Last but not least, positional only parameters allow us to use their names to be used in variable length keyword arguments. Check following example
>>> def f(a, b, /, **kwargs):
... print(a, b, kwargs)
...
>>> f(10, 20, a=1, b=2, c=3) # a and b are used in two ways
10 20 {'a': 1, 'b': 2, 'c': 3}
Positional-only parameters syntax was officially added to python3.8. Checkout what's new python3.8 - positional only arguments
PEP Related: PEP 570 -- Python Positional-Only Parameters

Haskell: function composition with anonymous/lambda function

While studying for a Functional Programming exam, I came across the following question from a previous test:
t1 = (reverse . take 2 . words . \ _ -> name)"!"
The task is to write the output of the statement. The variable name refers to the student's name, written in the form "Smith, John". If I enter the statement into WinHugs, I get the following output:
["John","Smith,"]
I understand what the functions reverse, take and words are doing and I understand how the . operator connects them. What I don't understand is what is happening here:
\ _ -> name
What are the slash, underscore and "arrow" for? Also, what does the exclamation point in quotation marks do? (nothing?)
It's a lambda function that discards its (only) argument (i.e. "!") and yields name.
As another lambda example, the following would be a lambda function that squares its argument:
\x -> x * x
The \ is the notation used to introduce a lambda function.
The _ means "variable about whose name we do not care".
The -> separates the lambda function's arguments from the expression used to specify its result.
What you are seeing there is an anonymous function, or lambda function (that name comes from lambda calculus). The backslash tells you that you are starting the function. The underscore says that the function takes one argument and ignores it. The arrow points from the argument list to the result - in this case, it ends up ignoring its argument and returning the name. Essentially, \_ -> name is the same as const name.
A constant anonymous function: which ever the argument, return name.
Haskell's lambda expressions (i.e. anonymous functions) come in this form:
\x -> f x
where x is an argument, and f x an expression using this argument. The special variable _ matches anything and treats it as unimportant.
The "slash" is part of a lambda function, the underscore is a "wildcard" used in patterns (it is discarded). The arrow is another part of the lambda function. The function \ _ -> name returns the name, regardless of input, so the "!" does nothing but provide (unused) input to the function.

Resources