how to insert new variable in (*args,**kwargs) section? - python

i want to make a decoration method to assign the variable which the function would use but wouldn't be deliver by itself.
for example add new variable y in lambda r,i wrote code in this way but didn't work.
r = lambda x:x+y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(y=y,*args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
this wouldn't work too
r = lambda x:x+y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(*args,**kwargs)
return wrapped
r = foo(r)
print(r(444))

kwargs is a casual python dict type, so you can just set the value of the y key to be 3
r = lambda x, y=0:x+y
def foo(func):
def wrapped(*args,**kwargs):
print type(kwargs) # will output <type 'dict'>
kwargs['y'] = 3
return func(*args,**kwargs)
return wrapped
In Understanding kwargs in Python this is explained in details.

Problem is that the function r can accept only one argument, you need to change its definition to accept more args:
r = lambda x, y=0, *args, **kwargs: x + y
def foo(func):
def wrapped(*args,**kwargs):
y = 3
return func(y=y, *args,**kwargs)
return wrapped
r = foo(r)
print(r(444))
#447

Related

List of functions->single function (in python)

Say that I have a list of functions: [f1, f2, f3] (in python)
How do I return a single function F:=f3(f2(f1())) (notice that F is of function type). I know that it's possible to do it with .reduce() but I was wondering if there's another way to do it without using libraries.
edit:
Also, notice that the length of the list can be greater than 3
I tried:
def func(list):
i = 1
new_function = filters[0]
while i<=len(filters)-1:
new_function = filters[i](new_function)
i+=1
return new_function
but it doesn't work
The problem in your code is that you pass a function as argument with filters[i](new_function).
I would suggest this recursive solution:
def chain(first, *rest):
return lambda x: first(chain(*rest)(x) if rest else x)
Example use:
def inc(x):
return x + 1
def double(x):
return x * 2
def square(x):
return x * x
f = chain(square, double, inc)
print(f(5)) # ((5+1)*2) ** 2 == 144
I see that in the code you tried, you never actually call the first of your functions. (I also assume that your code starts: def func(filters):
Taking into account that f1() takes no parameter, but the rest take the parameter of the return of the previous function, this should work:
def fit(funcs):
v = funcs[0]()
for f in funcs[1:]:
v = f(v)
return v
def f1():
return 42
def f2(x):
return x
def f3(x):
return x
fs = [f1, f2, f3]
a = lambda:fit(fs)
print(a())
Output: 42
def get_single_func(func_list):
def single_func(*args, **kwargs):
ret = func_list[0](*args, **kwargs)
for func in func_list[1:]:
ret = func(ret)
return ret
return single_func

Trying to create a function that repeats a function

I have a helping function:
def incr(x):
return x+1
I want to create a function named "repeated" that use "incr" function n times on a certain parameter
In the end I want to use the "repeated" function in this matter only :
repeated (incr, 4)(2)
That for example will output 6.
So far I tried to do this:
def repeated(f, n):
func, x = f
for i in range(n):
func(x)
But it gave me an error saying I can't unpack a non Tuple function.
It doesn't seem like I don't have access in the function to the "(2)"
I do not recommend to use such a syntax construct, for such a task:
repeated(incr, 4)(2)
Your repeated function must return another function, that will be called by (2).
This should work in your requested manner:
def incr(x):
return x+1
def repeated(f, x):
# function foo will be returned by repeated and called by (2)
def foo(n):
res = x
for i in range(n):
res = f(res)
return res
return foo
print(repeated(incr, 4)(2))
I think you may want to do something like functional programming.
Add args to deal with for different kind of function you want to repeat.
I can't confirm if there is a position argument what kind of results you want, so I didn't deal with it.
code:
import functools
def incr(x):
return x + 1
def incx(x,y = 0):
return x + y + 1
def repeated_inner(func,args,times):
head, *rest = args
for _ in range(times):
head = func(head, *rest)
return args[0]
def repeated(func, *args ):
return functools.partial(repeated_inner, func, args)
print(repeated(incr, 4)(2))
print(repeated(incx, 4)(2))
print(repeated(incx, 4 ,3)(2))
result
6
6
12
the repeatedfunction must return a function
def repeated(func, n):
def repeatedfunc(x):
rsl = x
for i in range(n):
rsl = func(rsl)
return rsl
return repeatedfunc
def incr(x):
return x+1
rslt = repeated(incr, 4)(2)
print(rslt)
output
6
You should write something like this:
def repeated(f, arg_0, n):
arg = arg_0
for i in range(n):
arg = f(arg)
return arg
In a more general situation:
def repeated(f, arg):
def n_f(n):
result = 0
for i in range(n):
result =f(arg)
return result
return n_f

Optimal way to apply a conditional If statement

I'm basically defining a set of parameters below in the Start() method. Most of the params will be the same except for the request.Continuation which can have a value of either 6 or 3. My thinking was to have a list of the symbols that would get the value 6 (in self.continuation) and just say something like "If in self.continuation, value=6, else 3".
I'm fairly new to python so this could be way off but I wasn't sure if this would be a good use case for a lambda expression.
class BarsRequestSample(CELEnvironment.CELSinkBase):
def __init__(self):
self.symbols = ['CLES12Z', 'HOE']
self.continuation=['ClES12Z', 'CLES6M']
def Start(self):
for symbol in self.symbols:
request.Symbol = symbol
request.RangeStart = 0
request.RangeEnd = -60
request.IntradayPeriod = 5
request.Continuation = 6
request.UpdatesEnabled = True
request.EqualizeCloses = True
request.SessionsFilter = 31
What I know I could do:
def Start(self):
for symbol in self.symbols:
request.Symbol = symbol
request.RangeStart = 0
request.RangeEnd = -60
request.IntradayPeriod = 5
#potential attempt
if symbol in self.continuation:
request.Continuation = 6
else:
request.Continuation = 3
request.UpdatesEnabled = True
request.EqualizeCloses = True
request.SessionsFilter = 31
I'm just getting an intuition that there may be a more concise way to do the same thing - would appreciate any thoughts!
I would make the list of symbols a set. Sets containment is an O(1) operation versus lists which are O(n). It doesn't matter for two elements, but it's a good habit to get into.
self.continuation = {'ClES12Z', 'CLES6M'}
You can use a conditional expression to condense the assignment to one line:
request.Continuation = 6 if symbol in self.continuation else 3
For lambda:
https://github.com/baruchel/continuation/blob/master/continuation/init.py
"""
A module for adding a call/cc feature to Python.
"""
__version__ = '0.1'
__internal_type_error__ = (
"Argument of a continuation must be a continuable function."
)
class _Continuation(Exception):
def __init__(self, f, args, kwargs):
self.func, self.args, self.kwargs = f, args, kwargs
class Continuation():
def __init__(self, calling_id):
self.calling_id = calling_id
def __callback__(self, f):
if isinstance(f, _Continuation):
f.uid = id(self)
raise f
raise TypeError(__internal_type_error__)
def __call__(self, f):
return lambda *args, **kwargs: self.__callback__(f(*args, **kwargs))
__lshift__ = __call__
def with_continuation(func):
def _w(*args, **kwargs):
return _Continuation(func, args, kwargs)
_w.__with_continuation_signature__ = True
return _w
class _with_CC():
def __call__(self, f):
try:
_ = f.__with_continuation_signature__
except AttributeError:
raise TypeError(__internal_type_error__)
return (
lambda *args, **kwargs:
_with_CC().__callback__(f(*args, **kwargs)))
__rshift__ = __call__
def __callback__(self, f):
k = Continuation(id(self))
i = id(k)
while True:
try:
return (f.func)(k)(*f.args, **f.kwargs)
except _Continuation as e:
if i == e.uid: f = e
else: raise e
with_CC = _with_CC()

how to override inner method function in outer

How to modify the code
def mackfunc(a):
def func(b):
return a+b
return func
f = mackfunc(1)
print(f(1))
print(f(2))
The output is 2 and 3
def mackfunc(a):
def func(b):
return a+b
return func
f = mackfunc(1)
add sth here to this out
print(f(1))
print(f(2))
I hope that the output here is 3 and 4
You can't. func is a local variable, which cannot be interfered with from outside the function. You can either redefine mackfunc entirely, or wrap it.
# redefine
def mackfunc(a):
def func(b):
return a + b + 1
return func
# wrap
orig_mackfunc = mackfunc
def mackfunc(a):
orig_func = orig_mackfunc(a)
def func(b):
return orig_func(b) + 1
return func
You can use a custom function inside you inner function and then redefine it later
def custom(arg):
return arg
def mackfunc(arg):
def func(b):
return custom(arg)+b
return func
f = mackfunc(1)
print(f(1))
print(f(2))
print()
def newcustom(arg):
return arg + 1
custom = newcustom
print(f(1))
print(f(2))
OUTPUT
2
3
3
4
Hope this helps. :)

Avoiding unnecessary key evaluations when sorting a list

I have a list which I want to sort by multiple keys, like:
L = [ ... ]
L.sort(key = lambda x: ( f(x), g(x) ))
This works fine. However, this results with unnecessary calls to g, which I would like to avoid (for being potentially slow). In other words, I want to partially and lazily evaluate the key.
For example, if f is unique over L (i.e. len(L) == len(set(map(f,L)))) no calls to g should be made.
What would be the most elegant/pythonic way to do this?
One way I can think of is to define a custom cmp function (L.sort(cmp=partial_cmp)), but IMO this is less elegant and more complicated than using the key parameter.
Another way would be to define a key-wrapper class which takes a generator expression to generate the different parts of the key, and override the comparison operators to compare one-by-one. However, I'm feeling there must be a simpler way...
EDIT: I'm interested in a solution for the general problem of sorting by multiple functions, not only two as in my example above.
You can try using itertools.groupby:
result = []
for groupKey, group in groupby(sorted(L, key=f), key=f):
sublist = [y for y in group]
if len(sublist) > 1:
result += sorted(sublist, key=g)
else:
result += sublist
Another possibility, even less elegant, but in place:
L.sort(key = f)
start = None
end = None
for i,x in enumerate(L):
if start == None:
start = i
elif f(x) == f(L[start]):
end = i
elif end == None:
start = i
else:
L[start:end+1] = sorted(L[start:end+1], key=g)
start = None
if start != None and end != None:
L[start:end+1] = sorted(L[start:end+1], key=g)
First version generalized to any number of functions:
def sortBy(l, keyChain):
if not keyChain:
return l
result = []
f = keyChain[0]
for groupKey, group in groupby(sorted(l, key=f), key=f):
sublist = [y for y in group]
if len(sublist) > 1:
result += sortBy(sublist, keyChain[1:])
else:
result += sublist
return result
The second version generalized to any number of functions (not fully in place though):
def subSort(l, start, end, keyChain):
part = l[start:end+1]
sortBy(part, keyChain[1:])
l[start:end+1] = part
def sortBy(l, keyChain):
if not keyChain:
return
f = keyChain[0]
l.sort(key = f)
start = None
end = None
for i,x in enumerate(l):
if start == None:
start = i
elif f(x) == f(l[start]):
end = i
elif end == None:
start = i
else:
subSort(l, start, end, keyChain)
start = i
end = None
if start != None and end != None:
subSort(l, start, end, keyChain)
Given a function, you could create a LazyComparer class like this:
def lazy_func(func):
class LazyComparer(object):
def __init__(self, x):
self.x = x
def __lt__(self, other):
return func(self.x) < func(other.x)
def __eq__(self, other):
return func(self.x) == func(other.x)
return lambda x: LazyComparer(x)
To make a lazy key function out of multiple functions, you could create a utility function:
def make_lazy(*funcs):
def wrapper(x):
return [lazy_func(f)(x) for f in funcs]
return wrapper
And together they could be used like this:
def countcalls(f):
"Decorator that makes the function count calls to it."
def _f(*args, **kwargs):
_f._count += 1
return f(*args, **kwargs)
_f._count = 0
return _f
#countcalls
def g(x): return x
#countcalls
def f1(x): return 0
#countcalls
def f2(x): return x
def report_calls(*funcs):
print(' | '.join(['{} calls to {}'.format(f._count, f.func_name)
for f in funcs]))
L = range(10)[::-1]
L.sort(key=make_lazy(f1, g))
report_calls(f1, g)
g._count = 0
L.sort(key=make_lazy(f2, g))
report_calls(f2, g)
which yields
18 calls to f1 | 36 calls to g
36 calls to f2 | 0 calls to g
The #countcalls decorator above is used to connfirm that when f1 returns a lot
of ties, g is called to break the ties, but when f2 returns distinct values,
g does not get called.
NPE's solution adds memoization within the Key class. With the solution above,
you could add memoization outside (independent of) the LazyComparer class:
def memo(f):
# Author: Peter Norvig
"""Decorator that caches the return value for each call to f(args).
Then when called again with same args, we can just look it up."""
cache = {}
def _f(*args):
try:
return cache[args]
except KeyError:
cache[args] = result = f(*args)
return result
except TypeError:
# some element of args can't be a dict key
return f(*args)
_f.cache = cache
return _f
L.sort(key=make_lazy(memo(f1), memo(g)))
report_calls(f1, g)
which results in fewer calls to g:
10 calls to f1 | 10 calls to g
You could use a key object that would lazily evaluate and cache g(x):
class Key(object):
def __init__(self, obj):
self.obj = obj
self.f = f(obj)
#property
def g(self):
if not hasattr(self, "_g"):
self._g = g(self.obj)
return self._g
def __cmp__(self, rhs):
return cmp(self.f, rhs.f) or cmp(self.g, rhs.g)
Here is an example of use:
def f(x):
f.count += 1
return x // 2
f.count = 0
def g(x):
g.count += 1
return x
g.count = 0
L = [1, 10, 2, 33, 45, 90, 3, 6, 1000, 1]
print sorted(L, key=Key)
print f.count, g.count

Categories