similar use of operator overloading in python functions - python

Is there a way to use variable like in operator overloading.
e.g.
a += 1
Instead of a = a + 1
in
a = max(a, some_other_variable)
The max() function is just an example.
NOTE:
My intent here is not to use the variable 'a' again, if possible. These two examples are different and not related to each other.
e.g.
a = some_function(a, b)
Here, the values returned from some_function() is assigned back to variable 'a' again.
Unless variable 'a' is a class variable I cannot access variable inside function some_function(), although if there is a way so that I can use it only once?

You cannot supplement Python's set of operators and statements directly in the Python code. However, you can write a wrapper that uses Python's language services to write a Pythonesque DSL which includes the operators you want.

I feel like you want something along these lines ...
>>> class Foo(object):
... def __iadd__(self, other):
... return max(self.num, other)
... def __init__(self, num):
... self.num = num
...
>>> a = Foo(5)
>>> a += 4
>>> print a
5
>>> a = Foo(4)
>>> a += 6
>>> a
6
But please note that I would consider this use of __iadd__ to be very impolite. Having __iadd__ return something other than self is generally inconsiderate if the type is mutable.

Instead of overloading an operator in a like the other answer, you could create a partial-like object for the second part. (I used the left shift operator for "coolness")
class partial(functools.partial):
def __rlshift__(self, val):
return self(val)
and use like this:
>>> a = 10
>>> a <<= partial(max, 20)
>>> a
20
So you don't need to mess with your variable types to execute the operation. Also you will not need to declare a new class for every function.
PS: Beware that the actual execution is max(20, a).

Related

pass a function name as argument and then check correctness

I'm aware that I cann pass a function name as an argument to another function i.e
def fun_passed(a,b):
#do something
def main_fun(arg,fun_passed):
#do something
#call main_fun
first_fun =fun_passed
main_fun(1,first_fun)
Inside main_fun how can I make some checks.
For example, Based on the function i passed i want to set a variable
def main_fun(1,fun_passed):
if fun_passed==first_fun:
i=1
else:
i=10
I can't simply use == because i think that comparison doesn't make sense.
Thanks
You can compare functions for equality, but it's not going to check if the two functions do the exact same thing. Such a check is, in general, undecidable in the technical sense.
Instead, f == g simply returns true if both f and g return to the same underlying object (i.e., it's the same as f is g). This means that something as simple as (lambda x: x) == (lambda x: x) evaluates as False.
You should use the is keyword:
def fct_a(a,b):
#do something
pass
def fct_b(a,b):
#do something
pass
def main_fun(fct):
if fct is fct_a:
print("fct is 'fct_a'")
else:
print("fct is not 'fct_a'")
main_fun(fct_a) # >> fct is 'fun_passed'
main_fun(fct_b) # >> fct is not 'fun_passed'
For more about the differences between is and ==, see there
If you are dealing with functions, not a lambda, the function object has a variable __name__ which shows the exact name of the original function. Here a simple example:
>>> def x():
... return 0;
...
>>> type(x)
<type 'function'>
>>> x.__name__
'x'
>>> y=x
>>> y.__name__
'x'
So in your case, it will be something like this
if fun_passed.__name__=="first_fun":

Python dynamic function attribute

I came across an interesting issue while trying to achieve dynamic sort.
Given the following code:
>>> l = []
>>> for i in range(2):
>>> def f():
>>> return f.v
>>> f.v = i
>>> l.append(f)
You have to be careful about how to use the functions in l:
>>> l[0]()
1
>>> l[1]()
1
>>> [h() for h in l]
[1, 1]
>>> [f() for f in l]
[0, 1]
>>> f = l[0]
>>> f()
0
>>> k = l[1]
>>> k()
0
>>> f = l[1]
>>> k()
1
>>> del f
>>> k()
NameError: global name 'f' is not defined
The behavior of the function depends on what f currently is.
What should I do to avoid this issue? How can I set a function attribute that does not depends on the function's name?
Update
Reading your comments and answers, here is my actual problem.
I have some data that I want to sort according to user input (so I don't know sorting criteria in advance). User can choose on which part of the data to apply successive sorts, and these sorts can be ascending or descending.
So my first try was to loop over the user inputs, define a function for each criterion, store this function in a list and then use this list for sorted's key like this: key=lambda x: [f(x) for f in functions]. To avoid multiplying conditions into functions themselves, I was computing some needed values before the function definition and binding them to the function (different functions with different pre-computed values).
While debugging, I understood that function attribute was not the solution here, so I indeed wrote a class with a __call__ method.
The issue is due to the fact that return f.v loads the global f, and not the one you intend.1 You can see this by disassembling the code:
>>> dis.dis(l[0])
3 0 LOAD_GLOBAL 0 (f)
3 LOAD_ATTR 1 (v)
6 RETURN_VALUE
After the loop that populates l, f is a reference to the last closure created, as you can see here:
>>> l
[<function f at 0x02594170>, <function f at 0x02594130>]
>>> f
<function f at 0x02594130>
Thus, when you call l[0](), it still loads the f that points to the last function created, and it returns 1. When you redefined f by doing f = l[0], then the global f now points to the first function.
What you seem to want is a function that has a state, which really is a class. You could therefore do something like this:
class MyFunction:
def __init__(self, v):
self.v = v
def __call__(self):
return self.v
l = [MyFunction(i) for i in range(2)]
l[0]() # 0
l[1]() # 1
Though it may be a good idea to explain your actual problem first, as there might be a better solution.
1: Why doesn't it load the global f and not the current instance, you may ask?
Recall that when you create a class, you need to pass a self argument, like so:
# ...
def my_method(self):
return self.value
self is actually a reference to the current instance of your object. That's how Python knows where to load the attribute value. It knows it has to look into the instance referenced by self. So when you do:
a.value = 1
a.my_method()
self is now a reference to a.
So when you do:
def f():
return f.v
There's no way for Python to know what f actually is. It's not a parameter, so it has to load it from elsewhere. In your case, it's loaded from the global variables.
Thus, when you do f.v = i, while you do set an attribute v for the instance of f, there's no way to know which instance you are referring to in the body of your function.
Note that what you are doing here:
def f():
return f.v
is not making a function which returns whatever its own v attribute is. It's returning whatever the f object's v attribute is. So it necessarily depends on the value of f. It's not that your v attribute "depends on the function's name". It really has nothing at all to do with the function's name.
Later, when you do
>>> f = l[0]
>>> k = l[1]
>>> k()
0
What you have done is bound k to the function at l[1]. When you call it, you of course get f.v, because that's what the function does.
But notice:
>>> k.v
1
>>> [h.v for h in l]
[0, 1]
So, a function is an object, and just like most objects, it can have attributes assigned to it (which you can access using dot notation, or the getattr() function, or inspecting the object's dictionary, etc.). But a function is not designed to access its own attributes from within its own code. For that, you want to use a class (as demonstrated by #VincentSavard).
In your particular case, the effect you seem to be after doesn't really need an "attribute" per se; you are apparently looking for a closure. You can implement a closure using a class, but a lighter-weight way is a nested function (one form of which is demonstrated by #TomKarzes; you could also use a named inner function instead of lambda).
Try this:
l = []
for i in range(2):
def f(n):
return lambda: n
l.append(f(i))
This doesn't use attributes, but creates a closure for each value of i. The value of n is then locked once f returns. Here's some sample output:
>>> [f() for f in l]
[0, 1]
As others said, return f.v looks for f name in the current scope which is equal to the last defined function.
To work around this you can simulate functions:
>>> class Function(object):
... def __init__(self, return_value):
... self.return_value = return_value
... def __call__(self):
... return self.return_value
...
>>> l = []
>>> for i in range(2):
... l.append(Function(i))
...
>>> l[0]()
>>> 0
>>> l[1]()
>>> 1

How to change the look of Python operators?

In order to make Python look more familiar, I've tried to assign an operator symbol to a variable's name,just for educational purposes: import operator equals = operator.eq
This seems to work fine for equals(a,b) but not for a equals b
Is there a way to express that a equals b instead of a == b
No, Python (and most mainstream languages) does not allow this kind of customization. In Python the restriction is quite intentional — an expression such as a equals b would look ungrammatical to any reader familiar with Python.
Not necessarily, but another SO answer shows how you can use this simple trick to "create" new operators. However, they only work if you surround the operator by | | or by << >>:
equals = Infix(lambda x, y: x == y):
print 2 |equals| 2 # True
The best you can do is
def equals(a,b):
return a == b
equals(1,5)
>> False
or
class my:
value = 0
def equals(self, b):
return self.value == b
a = my()
a.equals(3)
>>False
But you should use the built-in operator for readability. This way, a reader can distinguish, at once, an operator, a function, a symbol (a variable), a member function, etc...

How to rebind names in outer function?

>>> def QQ():
... a = 0
... def QQQ():
... global a
... a += 1
... QQQ()
...
>>> QQ()
NameError: global name 'a' is not defined
It appears that global doesn't work in this scenario. What else can I do, other than the 1-element list trick?
If you're using Python 3.x, you can use nonlocal:
>>> def QQ():
... a = 0
... def QQQ():
... nonlocal a
... a += 1
... QQQ()
... return a
...
>>> QQ()
1
If you're using Python 2.x, you can't do it. That's why nonlocal was added. So, you have to use some kind of mutable wrapper, like the 1-element list trick.*
PEP 3104 explains all of the gory details (including why Python doesn't do "classic static nested scoping" by default, and requires you to be explicit about it).
* Or upgrade to 3.x, of course. Whenever you find yourself asking how to bind to nonlocals, delegate to another generator, get fully-qualified class names, specify keyword-only parameters, unpack a variable-length iterator but capture the last value separately, or anything else that's trivial in 3.x but painful in 2.x, it's worth re-asking yourself whether it's time to upgrade.
Instead of creating an arbitrary list you could use the built in *args and **kwargs something like
def f(**kwargs):
kwargs['start'] = kwargs.get('start', 0)
def g():
kwargs['start'] += 1
return kwargs['start']
return g
it's essentially the same "hack", this is just less ugly imo.

Is there a way to refer to the current function in python?

I want a function to refer to itself. e.g. to be recursive.
So I do something like that:
def fib(n):
return n if n <= 1 else fib(n-1)+fib(n-2)
This is fine most of the time, but fib does not, actually, refer to itself; it refers to the the binding of fib in the enclosing block. So if for some reason fib is reassigned, it will break:
>>> foo = fib
>>> fib = foo(10)
>>> x = foo(8)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fib
TypeError: 'int' object is not callable
How can I prevent this from happening (from inside fib), if at all possible? As far as I know, the name of fib does not exist before the function-definition is fully executed; Are there any workarounds?
I don't have a real use case where it may actually happen; I am asking out of sheer curiosity.
I'd make a decorator for this
from functools import wraps
def selfcaller(func):
#wraps(func)
def wrapper(*args, **kwargs):
return func(wrapper, *args, **kwargs)
return wrapper
And use it like
#selfcaller
def fib(self, n):
return n if n <= 1 else self(n-1)+self(n-2)
This is actually a readable way to define a Fixed Point Combinator (or Y Combinator):
fix = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))
usage:
fib = fix(lambda self: lambda n: n if n <= 1 else self(n-1)+self(n-2))
or:
#fix
def fib(self):
return lambda n: n if n <= 1 else self(n-1)+self(n-2)
The binding here happens in the formal parameter, so the problem does not arise.
There's no way to do what you're trying to do. You're right that fib does not exist before the function definition is executed (or, worse, it exists but refers to something completely different…), which means there is no workaround from inside fib that can possibly work.*
However, if you're willing to drop that requirement, there are workarounds that do work. For example:
def _fibmaker():
def fib(n):
return n if n <= 1 else fib(n-1)+fib(n-2)
return fib
fib = _fibmaker()
del _fibmaker
Now fib is referring to the binding in the closure from the local environment of a call to _fibmaker. Of course even that can be replaced if you really want to, but it's not easy (the fib.__closure__ attribute is not writable; it's a tuple, so you can't replace any of its cells; each cell's cell_contents is a readonly attribute, …), and there's no way you're going to do it by accident.
There are other ways to do this (e.g., use a special placeholder inside fib, and a decorator that replaces the placeholder with the decorated function), and they're all about equally unobvious and ugly, which may seem to violate TOOWTDI. But in this case, the "it" is something you probably don't want to do, so it doesn't really matter.
Here's one way you can write a general, pure-python decorator for a function that uses self instead of its own name, without needing an extra self parameter to the function:
def selfcaller(func):
env = {}
newfunc = types.FunctionType(func.__code__, globals=env)
env['self'] = newfunc
return newfunc
#selfcaller
def fib(n):
return n if n <= 1 else self(n-1)+self(n-2)
Of course this won't work on a function that has any free variables that are bound from globals, but you can fix that with a bit of introspection. And, while we're at it, we can also remove the need to use self inside the function's definition:
def selfcaller(func):
env = dict(func.__globals__)
newfunc = types.FunctionType(func.__code__, globals=env)
env[func.__code__.co_name] = newfunc
return newfunc
This is Python 3.x-specific; some of the attribute names are different in 2.x, but otherwise it's the same.
This still isn't 100% fully general. For example, if you want to be able to use it on methods so they can still call themselves even if the class or object redefines their name, you need slightly different tricks. And there are some pathological cases that might require building a new CodeType out of func.__code__.co_code. But the basic idea is the same.
* As far as Python is concerned, until the name is bound, it doesn't exist… but obviously, under the covers, the interpreter has to know the name of the function you're defining. And at least some interpreters offer non-portable ways to get at that information.
For example, in CPython 3.x, you can very easily get the name of the function currently being defined—it's just sys._getframe().f_code.co_name.
Of course this won't directly do you any good, because nothing (or the wrong thing) is bound to that name. But notice that f_code in there. That's the current frame's code object. Of course you can't call a code object directly, but you can do so indirectly, either by generating a new function out of it, or by using bytecodehacks.
For example:
def fib2(n):
f = sys._getframe()
fib2 = types.FunctionType(f.f_code, globals=globals())
return n if n<=1 else fib2(n-1)+fib2(n-2)
Again, this won't handle every pathological case… but the only way I can think of to do so is to actually keep a circular reference to the frame, or at least its globals (e.g., by passing globals=f.f_globals), which seems like a very bad idea.
See Frame Hacks for more clever things you can do.
Finally, if you're willing to step out of Python entirely, you can create an import hook that preprocesses or compiles your code from a Python custom-extended with, say, defrec into pure Python and/or bytecode.
And if you're thinking "But that sounds like it would be a lot nicer as a macro than as a preprocessor hack, if only Python had macros"… then you'll probably prefer to use a preprocessor hack that gives Python macros, like MacroPy, and then write your extensions as macros.
Like abamert said "..there is no way around the problem from inside ..".
Here's my approach:
def fib(n):
def fib(n):
return n if n <= 1 else fib(n-1)+fib(n-2)
return fib(n)
Someone asked me for a macro based solution for this, so here it is:
# macropy/my_macro.py
from macropy.core.macros import *
macros = Macros()
#macros.decorator()
def recursive(tree, **kw):
tree.decorator_list = []
wrapper = FunctionDef(
name=tree.name,
args=tree.args,
body=[],
decorator_list=tree.decorator_list
)
return_call = Return(
Call(
func = Name(id=tree.name),
args = tree.args.args,
keywords = [],
starargs = tree.args.vararg,
kwargs = tree.args.kwarg
)
)
return_call = parse_stmt(unparse_ast(return_call))[0]
wrapper.body = [tree, return_call]
return wrapper
This can be used as follows:
>>> import macropy.core.console
0=[]=====> MacroPy Enabled <=====[]=0
>>> from macropy.my_macro import macros, recursive
>>> #recursive
... def fib(n):
... return n if n <= 1 else fib(n-1)+fib(n-2)
...
>>> foo = fib
>>> fib = foo(10)
>>> x = foo(8)
>>> x
21
It basically does exactly the wrapping that hus787 gave:
Create a new statement which does return fib(...), which uses the argument list of the original function as the ...
Create a new def, with the same name, same args, same decorator_list as the old one
Place the old function, together followed by the return statement, in the body of the new functiondef
Strip the original function of its decorators (I assume you'd want to decorate the wrapper instead)
The parse_stmt(unparse_ast(return_call))[0] rubbish is a quick hack to get stuff to work (you actually can't just copy the argument AST from the param list of the function and use them in a Call AST) but that's just detail.
To show that it's actually doing that, you can add a print unparse_ast statement to see what the transformed function looks like:
#macros.decorator()
def recursive(tree, **kw):
...
print unparse_ast(wrapper)
return wrapper
which, when run as above, prints
def fib(n):
def fib(n):
return (n if (n <= 1) else (fib((n - 1)) + fib((n - 2))))
return fib(n)
Looks like exactly what you want! It should work for any function, with multiple args, kwargs, defaults, etc., but I'm too lazy to test. Working with the AST is a bit verbose, and MacroPy is still super-experimental, but i think it's pretty neat.

Categories

Resources