Python splat-in-the-middle - python-3.x

You can put splat arguments in the middle rather than at the end (only in python 3 it seems):
import functools
def wierd_sum(use_str_cat=False, *args, use_product=False):
if use_str_cat:
return ''.join([str(a) for a in args])
elif use_product:
return functools.reduce(lambda a,b : a*b, args)
else:
return functools.reduce(lambda a,b : a+b, args)
Now how do you use said function?
print(wierd_sum(1, 2, 3)) # 23 -> Concatenation, 1 counts as True.
print(wierd_sum(False, 2, 3, 4, 5, True)) # 15 -> Addition, True counts as 1.
print(wierd_sum(False, 2, 3, 4, 5, use_product=True)) # 120 -> Multiplication 2*3*4*5
print(wierd_sum(use_str_cat=True, 1, 2, 3)) # SyntaxError: positional argument follows keyword argument.
print(wierd_sum(1, 2, 3, use_str_cat=False)) # TypeError: wierd_sum() got multiple values for argument 'use_str_cat'
My question is, is there ever, ever, EVER a reason to do such a thing?

This is to allow for keyword only arguments; similar to positional-only arguments (comparison here).
Ideally though, unless you actually need the varargs, you should omit the name to disallow varargs from being supplied:
def my_func(a, *, keyword_only=True):
pass
my_func(1, 2) # TypeError: my_func() takes 1 positional argument but 2 were given
my_func(1, keyword_only=2) # Fine

Related

Default array parameters python

I need to understand why the calls to this function amends to the array which got a default initialization in the function declaration? Appreciate if any reference to the API specs
def f(i, values = []):
values.append(i)
print(values)
return values
Calls to:
f(1) prints -> [1]
f(2) prints -> [1, 2]
f(3) prints -> [1, 2, 3]
and so one

Using map python with key argument

I have a function that looks like this:
def myFunct(arg1=None,arg2=None,arg3=None):
pass
I would like to use that function with a map function but with argument 1 and 3 only.
idea would be:
map(myFunct,list_arg1,list_arg3)
so each of the call would be myFunct(value1,arg3=value3)
How could I achieve that ?
You could use lambda to map the arguments to your keyword arguments.
def foo(arg1=None, arg2=None, arg3=None):
return arg1 + arg3
list1 = [3, 4, 5]
list2 = [5, 6, 7]
print(list(map(lambda x, y: foo(arg1=x, arg3=y), list1, list2)))
Another approach is to keep your function as is and modify what you are mapping over:
from itertools import repeat
def f(x = 0, y = 0, z = 0):
return sum((x,y,z))
map(f,range(1,10),repeat(0),range(21,30))
Although from a readability point of view, a simple generator expression might be preferable to any solution based on map, something along the lines of:
f(x = i,z = j) for i,j in zip(range(1,10),range(21,30)))

Everytime I run this code it says that numpy.ndarray has not attribute 'index'

When I run this code it returns that the numpy.ndarray object has no attributes. I'm trying to write a function that in case the number given is in the array will return with the position of that number in the array.
a = np.c_[np.array([1, 2, 3, 4, 5])]
x = int(input('Type a number'))
def findelement(x, a):
if x in a:
print (a.index(x))
else:
print (-1)
print(findelement(x, a))
Please use np.where instead of list.index.
import numpy as np
a = np.c_[np.array([1, 2, 3, 4, 5])]
x = int(input('Type a number: '))
def findelement(x, a):
if x in a:
print(np.where(a == x)[0][0])
else:
print(-1)
print(findelement(x, a))
Result:
Type a number: 3
2
None
Note np.where returns the indices of elements in an input array where
the given condition is satisfied.
You should check out np.where and np.argwhere.

Evaluating the output of multiple functions which return True or False

So I came across this interesting problem.It basically is a lot of functions which return True or False within a function and I want that secondary function to return either True or False based on applying an AND or OR logic to all of the functions within it. I know this is a terrible way to explain so let's see some code which will hopefully explain it better
#this is the first function that return True or False
def f(x):
if x == 1:
return True
elif x == 0:
return False
#this is the function that takes the first one and I want it to return either True or False based on an AND logic
def g(f):
f(1)
f(0)
f(0)
f(1)
f(1)
f(0)
f(1)
Now I know I can just write the second function with 'and' between all the f(x) functions that I call but that seems very ugly and so I want something that will just evaluate all of these and return me a value. I don't enough experience with writing methods which take in multiple inputs and also multiple inputs that vary so I would appreciate any help on this.
You can use all and a comprehension over the variable arguments (*args) of the funtion:
>>> def f(x):
... if x == 1:
... return True
... elif x == 0:
... return False
...
>>> def g(f, *args):
... return all(f(x) for x in args)
...
>>> g(f, 1, 0, 0, 1)
False
>>> g(f, 1, 1, 1)
True
You can use the existing all function that is equivalent to a logical AND:
def f(x):
return x < 5
all((f(1), f(2), f(3), f(4)))
Now concerning function g you can do this (for example):
def g(f, inputs):
for i in inputs:
yield f(i)
all(g(f, range(5)))
Here you can replace range(5) with any of [0, 1, 2, 3, 4], (0, 1, 2, 3, 4), {0, 1, 2, 3, 4}, and many more (ie. any iterable).
Note that a function similar to g also exists in python, it's called map, you could use it this way:
all(map(f, range(5))) # More or less equivalent to all(g(f, range(5)))
You could also directly make use a generator expression (an alternative to the yield generator form):
all(f(i) for i in range(5))
Which one of this solution is the best really depend on the use case and on your personal preferences (even if the last one is probably the one you will most commonly see).
For AND function, you can use python's all, and for OR function, you can use python's any
>>> all([True, False])
False
>>> all([True, True])
True
>>> any([True, False])
True
>>> any([True, True])
True
>>> any([False, False])
False
Just append all your outputs in a list, and evaluate all or any, so considering function f you defined
print(all([f(1),f(1)]))
print(all([f(0),f(0)]))
print(any([f(1), f(0)]))
print(any([f(0), f(0)]))
#True
#False
#True
#False

python 3 function with one argument returning list of integers

how the 're' function should look like if it must receive just one argument 's' and must return a list with the numbers (integers) from 1 to 12 incl. (for example)?
so the result in the interactive console have to be:
>>> re(12)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
First of all you used def incorrectly, if you want to define you have to enter : and define function in additional indentation below, or if you want to use function, you have to remove def.
Python has built-in range() immutable sequence type, which takes one to three arguments start, stop and step, in this case we only will use first two. However to get list we also need to use another built-in, which is mutable sequence type - list(), you can read more about lists in here. We will use list() as the type constructor: list() or list(iterable) as specified in built-in types page:
Lists may be constructed in several ways:
Using a pair of square brackets to denote the empty list: []
Using square brackets, separating items with commas: [a], [a, b, c]
Using a list comprehension: [x for x in iterable]
Using the type constructor: list() or list(iterable)
The constructor builds a list whose items are the same and in the same
order as iterable’s items. iterable may be either a sequence, a
container that supports iteration, or an iterator object. If iterable
is already a list, a copy is made and returned, similar to
iterable[:]. For example, list('abc') returns ['a', 'b', 'c'] and
list( (1, 2, 3) ) returns [1, 2, 3]. If no argument is given, the
constructor creates a new empty list, [].
Now that we understand how list() works, we can go back to range() usage:
The arguments to the range constructor must be integers (either built-in int or any object that implements the index special
method). If the step argument is omitted, it defaults to 1. If the
start argument is omitted, it defaults to 0. If step is zero,
ValueError is raised.
For a positive step, the contents of a range r are determined by the formula r[i] = start + step*i where i >= 0 and r[i] < stop.
For a negative step, the contents of the range are still determined by the formula r[i] = start + step*i, but the constraints
are i >= 0 and r[i] > stop.
A range object will be empty if r[0] does not meet the value constraint. Ranges do support negative indices, but these are
interpreted as indexing from the end of the sequence determined by the
positive indices.
Ranges containing absolute values larger than sys.maxsize are permitted but some features (such as len()) may raise OverflowError.
Range examples:
>>>
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(range(0, 30, 5))
[0, 5, 10, 15, 20, 25]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> list(range(0))
[]
>>> list(range(1, 0))
[]
Ranges implement all of the common sequence operations except concatenation and repetition (due to the fact that range objects can
only represent sequences that follow a strict pattern and repetition
and concatenation will usually violate that pattern).
start:
The value of the start parameter (or 0 if the parameter was not supplied)
stop:
The value of the stop parameter
step:
The value of the step parameter (or 1 if the parameter was not supplied)
Many other operations also produce lists, including the sorted() built-in.
The answer to your question looks like that:
def re(ending_number):
return list(range(1, ending_number + 1))
list_of_twelve = re(12) # list_of_twelve will contain [1, 2, ..., 12]
I would avoid using "re" as a function name, since re is also a python library for regex expressions.
Lycopersicum's answer does a good job of explaining range(), which is the fastest and most straight-forward way of approaching your problem. In general, it is best to use Python's built-in functions, that's because it will use Python's compiled C code rather than slower Python code.
I just thought I'd share a little bit about why you should use Range().
So, there are other ways to generate a list of numbers. First generate a list directly using a loop.
def listOfNumbers (number):
start = 1
listOf = []
while (start <= number):
listOf.append(start)
start = start + 1
return listOf
In this case, you simply use listOfNumbers(12) and you will get a list of numbers. However, this stores a list in memory and is slow, so not good for very large numbers.
On the other hand, you could use a generator (which is very much like range()). A generator does not store data in a list. Instead, it just "yields" numbers one at a time until the code stops. It's much faster:
def generatorOfNumbers (number):
start = 1
while start <= number:
yield start
start += 1
Then you can call it one of two ways to produce a list:
def listFromGenerator1 (number):
return [x for x in generatorOfNumbers(number)]
def listFromGenerator2 (number):
return list(generatorOfNumbers (number))
When I time these approaches I get.
timed(listOfNumbers) # time for list of 10000
...
Elapsed Time: 2.16007232666
Elapsed Time: 1.32894515991
Elapsed Time: 2.09093093872
Elapsed Time: 1.99699401855
Elapsed Time: 3.2000541687
... timed(listFromGenerator1)
...
Elapsed Time: 1.33109092712
Elapsed Time: 1.30605697632
Elapsed Time: 1.93309783936
Elapsed Time: 1.79386138916
Elapsed Time: 1.90401077271
... timed(listFromGenerator2)
...
Elapsed Time: 0.869989395142
Elapsed Time: 1.08408927917
Elapsed Time: 1.65319442749
Elapsed Time: 1.53398513794
Elapsed Time: 1.36089324951
... timed(listFromRange) # Lycopersicum's approach
...
Elapsed Time: 0.346899032593
Elapsed Time: 0.284194946289
Elapsed Time: 0.282049179077
Elapsed Time: 0.295877456665
Elapsed Time: 0.303983688354
In conclusion, always use built-in functions whenever possible rather than trying to build your own. That includes the (slight) preference for list() vs a list comprehension.

Resources