Rewriting Python switch into a more compact way [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Replacements for switch statement in python?
Suppose I have a list in Python:
list = ('ADD', 'SUB', 'PUSH', 'POP')
I want to run a function depending on input, and that input can be any value in the list.
Instead of writing a switch case statement for each element in list, is there a more compact way of writing it?
My reasoning is for the case of the list growing in the future.

Well, there is no switch/case statement in Python.
For a small list, you want to use if/elif:
def do_stuff(x, *args):
if x == 'ADD':
return do_add(*args)
elif x == 'SUB':
return do_sub(*args)
# …
else:
raise RuntimeError('Never heard of {}'.format(x))
For a larger list, you want to make sure each case is a function (I already assumed that above, but if you had code like return args[0] + args[1], you'd have to change that into a do_add function), and create a dict mapping names to functions:
func_map = {'ADD': do_add, 'SUB': do_sub, … }
def do_stuff(x, *args):
try:
return func_map[x](*args)
except KeyError:
raise RuntimeError('Never heard of {}'.format(x))
This works because in Python, functions are normal objects that you can pass around like any other objects. So, you can store them in a dict, retrieve them from the dict, and still call them.
By the way, this is all explained in the FAQ, along with a bit of extra fanciness.
If you have some default function you'd like to call instead of raising an error, it's obvious how to do that with the if/elif/else chain, but how do you do it with the dict map? You could do it by putting the default function into the except block, but there's an easier way: just use the dict.get method:
def do_stuff(x, *args):
return func_map.get(x, do_default)(*args)

You could also use a pattern such as this (in a hurry so can't clean it up atm):
>>> class Test(object):
... def test_FOO(self):
... print 'foo'
...
... def test_BAR(self):
... print 'bar'
...
>>> def run_on(cls, name):
... getattr(cls, 'test_%s' % name)()
...
>>> run_on(Test(), 'FOO')
foo

Related

Pass boolean argument by reference [duplicate]

This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 9 months ago.
In C++ you can always pass something as reference and anything that happens within the callee would be known to caller by just examining the referenced variable.
Imagine this scenario:
def x():
a = f()
print(a)
def f():
return "hello"
What I want is add a boolean flag that returns from f to x. There are several ways to do that:
make f return a tuple (str,bool)
pass a reference to a boolean variable into f
option 1 is currently not possible since there are many callers to f() and I cant change them to accept tuple as return value, so it must stay as it is.
option 2 is not possible since boolean argument is immutable (as I've learned recently).
Only f can calculate the boolean value, and x needs to know about it.
Is there any good way to achieve that? Looking for something that is not bad practice in Python coding in general.
The option that's closest to passing a pointer/reference into f would be to pass it a mutable object, like a list:
def f(ok=None):
if isinstance(ok, list):
ok.append(True)
return "hello"
def x():
ok = []
a = f(ok)
print(a, ok.pop())
But the better solution IMO would be to return a tuple, and refactor that behavior into a new function so that you're sharing code without disturbing the existing API:
def f_with_flag():
return "hello", True
def f():
return f_with_flag()[0]
def x():
a, ok = f_with_flag()
print(a, ok)

Adding items to a list if it's not a function

I'm trying to write a function right now, and its purpose is to go through an object's __dict__ and add an item to a dictionary if the item is not a function.
Here is my code:
def dict_into_list(self):
result = {}
for each_key,each_item in self.__dict__.items():
if inspect.isfunction(each_key):
continue
else:
result[each_key] = each_item
return result
If I'm not mistaken, inspect.isfunction is supposed to recognize lambdas as functions as well, correct? However, if I write
c = some_object(3)
c.whatever = lambda x : x*3
then my function still includes the lambda. Can somebody explain why this is?
For example, if I have a class like this:
class WhateverObject:
def __init__(self,value):
self._value = value
def blahblah(self):
print('hello')
a = WhateverObject(5)
So if I say print(a.__dict__), it should give back {_value:5}
You are actually checking if each_key is a function, which most likely is not. You actually have to check the value, like this
if inspect.isfunction(each_item):
You can confirm this, by including a print, like this
def dict_into_list(self):
result = {}
for each_key, each_item in self.__dict__.items():
print(type(each_key), type(each_item))
if inspect.isfunction(each_item) == False:
result[each_key] = each_item
return result
Also, you can write your code with dictionary comprehension, like this
def dict_into_list(self):
return {key: value for key, value in self.__dict__.items()
if not inspect.isfunction(value)}
I can think of an easy way to find the variables of an object through the dir and callable methods of python instead of inspect module.
{var:self.var for var in dir(self) if not callable(getattr(self, var))}
Please note that this indeed assumes that you have not overrided __getattr__ method of the class to do something other than getting the attributes.

str.format() with lazy dict?

I want to use str.format() and pass it a custom lazy dictionary.
str.format() should only access the key in the lazy dict it needs.
Is this possible?
Which interface needs to be implemented by the lazy_dict?
Update
This is not what I want:
'{0[a]}'.format(d)
I need something like this:
'{a}'.format(**d)
Need to run on Python2.7
For doing '{a}'.format(**d), especially the **d part, the "lazy" dict is transformed into a regular one. Here happens the access to all keys, and format() can't do anything about it.
You could craft some proxy objects which are put in place of the elements, and on string access they do the "real" work.
Something like
class LazyProxy(object):
def __init__(self, prx):
self.prx = prx
def __format__(self, fmtspec):
return format(self.prx(), fmtspec)
def __repr__(self):
return repr(self.prx())
def __str__(self):
return str(self.prx())
You can put these elements into a dict, such as
interd = { k, LazyProxy(lambda: lazydict[k]) for i in lazydict.iterkeys()}
I didn't test this, but I think this fulfills your needs.
After the last edit, it now works with !r and !s as well.
You can use the __format__ method (Python 3 only). See the doc here.
If I understand your question correctly, you want to pass a custom dictionary, that would compute values only when needed. First, we're looking for implementation of __getitem__():
>>> class LazyDict(object):
... def __init__(self, d):
... self.d = d
... def __getitem__(self, k):
... print k # <-- tracks the needed keys
... return self.d[k]
...
>>> d = D({'a': 19, 'b': 20})
>>> '{0[a]}'.format(d)
a
'19'
This shows that only key 'a' is accessed; 'b' is not, so you already have your lazy access.
But also, any object attribute is usable for str.format this way, and using #property decorator, you can access function results:
class MyObject(object):
def __init__(self):
self.a = 19
self.b = 20
def __getitem__(self, var):
return getattr(self, var)
# this command lets you able to call any attribute of your instance,
# or even the result of a function if it is decorated by #property:
#property
def c(self):
return 21
Example of usage:
>>> m = MyObject()
>>> '{0[c]}'.format(m)
'21'
But note that this also works, making the formating string a little bit specific, but avoid the need for __getitem__() implementation.
>>> '{0.c}'.format(m)
'21'

similar use of operator overloading in python functions

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).

Python - Passing a function into another function [duplicate]

This question already has answers here:
Python function as a function argument?
(10 answers)
Closed last month.
I am solving a puzzle using python and depending on which puzzle I am solving I will have to use a special set of rules. How can I pass a function into another function in Python?
Example
def Game(listA, listB, rules):
if rules == True:
do...
else:
do...
def Rule1(v):
if "variable_name1" in v:
return False
elif "variable_name2" in v:
return False
else:
return True
def Rule2(v):
if "variable_name3" and "variable_name4" in v:
return False
elif "variable_name4" and variable_name1 in v:
return False
else:
return True
This is just a pseudo code and therefore not specific but I get the code to compile but I need to know how to call the function Game and whether it's correctly defined since rules will be switched for either Rule1(v) or Rule2(v).
Just pass it in like any other parameter:
def a(x):
return "a(%s)" % (x,)
def b(f,x):
return f(x)
print b(a,10)
Treat function as variable in your program so you can just pass them to other functions easily:
def test ():
print "test was invoked"
def invoker(func):
func()
invoker(test) # prints test was invoked
For passing both a function, and any arguments to the function:
from typing import Callable
def looper(fn: Callable, n:int, *args, **kwargs):
"""
Call a function `n` times
Parameters
----------
fn: Callable
Function to be called.
n: int
Number of times to call `func`.
*args
Positional arguments to be passed to `func`.
**kwargs
Keyword arguments to be passed to `func`.
Example
-------
>>> def foo(a:Union[float, int], b:Union[float, int]):
... '''The function to pass'''
... print(a+b)
>>> looper(foo, 3, 2, b=4)
6
6
6
"""
for i in range(n):
fn(*args, **kwargs)
Depending on what you are doing, it could make sense to define a decorator, or perhaps use functools.partial.
Just pass it in, like this:
Game(list_a, list_b, Rule1)
and then your Game function could look something like this (still pseudocode):
def Game(listA, listB, rules=None):
if rules:
# do something useful
# ...
result = rules(variable) # this is how you can call your rule
else:
# do something useful without rules
A function name can become a variable name (and thus be passed as an argument) by dropping the parentheses. A variable name can become a function name by adding the parentheses.
In your example, equate the variable rules to one of your functions, leaving off the parentheses and the mention of the argument. Then in your game() function, invoke rules( v ) with the parentheses and the v parameter.
if puzzle == type1:
rules = Rule1
else:
rules = Rule2
def Game(listA, listB, rules):
if rules( v ) == True:
do...
else:
do...

Categories

Resources