Default parameter value for objects - python

Python provides a way to set a default value for function parameters. An example is:
def f(x=3):
print(x)
This is for a primitive type, lets try with objects:
def f(x=list()):
print(id(x))
f()
44289920
f()
44289920
Same object! I was surprised of this being used to the C/C++ way. Done with that, I now understand the default value is not build at invoking time but at definition time.
So I came to a solution:
def f(x=list()):
if len(x) == 0:
x = list()
print(id(x))
Solved! But at what price: In my opinion this doesn't seem to be a very clean solution.
This solution rely in the use of len(x) == 0 as a way to identify the default value which is Ok for my function but not for others so the solution can be generalized as:
def f(x=None):
if x is None:
x = list()
This can be shortened to:
def f(x=None):
x = x or list() # a bit shorter version
My question is, is there any shorter or better way to solve this problem? Will it ever be?

I still prefer the is None approach, but here is a new option to think about: If is defined only the type, you create a new instance of it.
def f(x=list):
if isinstance(x, type): x = x()
print(id(x))

Related

Argument passing by reference to a class in python (รก la C++), to modify it with the class methods

In this case, I want that the program print "X = changed"
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
self.var = 'changed'
X = 'unchanged'
V = Clase(X)
V.set_var()
print "X = ",X
All values are objects and are passed by reference in Python, and assignment changes the reference.
def myfunc(y):
y = 13
x = 42 # x now points at the integer object, 42
myfunc(y) # inside myfunc, y initially points to 42,
# but myfunc changes its y to point to a
# different object, 13
print(x) # prints 42, since changing y inside myfunc
# does not change any other variable
It's important to note here that there are no "simple types" as there are in other languages. In Python, integers are objects. Floats are objects. Bools are objects. And assignment is always changing a pointer to refer to a different object, whatever the type of that object.
Thus, it's not possible to "assign through" a reference and change someone else's variable. You can, however, simulate this by passing a mutable container (e.g. a list or a dictionary) and changing the contents of the container, as others have shown.
This kind of mutation of arguments through pointers is common in C/C++ and is generally used to work around the fact that a function can only have a single return value. Python will happily create tuples for you in the return statement and unpack them to multiple variables on the other side, making it easy to return multiple values, so this isn't an issue. Just return all the values you want to return. Here is a trivial example:
def myfunc(x, y, z):
return x * 2, y + 5, z - 3
On the other side:
a, b, c = myFunc(4, 5, 6)
In practice, then, there is rarely any reason to need to do what you're trying to do in Python.
In python list and dict types are global and are passed around by reference. So if you change the type of your variable X to one of those you will get the desired results.
[EDIT: Added use case that op needed]
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
self.var.test = 'changed'
class ComplicatedClass():
def __init__(self, test):
self.test = test
X = ComplicatedClass('unchanged')
print('Before:', X.test)
V = Clase(X)
V.set_var()
print("After:",X.test)
>>> Before: unchanged
>>> After: changed
strings are immutable so you could not change X in this way
... an alternative might be reassigning X in the global space... this obviously will fail in many many senarios (ie it is not a global)
class Clase:
def __init__(self,variable):
self.var = variable
def set_var(self):
globals()[self.var] = 'changed'
X = 'unchanged'
V = Clase('X')
V.set_var()
print "X = ",X
the other alternative is to use a mutable data type as suggested by Ashwin
or the best option is that this is probably not a good idea and you should likely not do it...

python generator endless stream without using yield

i'm trying to generate an endless stream of results given a function f and an initial value x
so first call should give the initial value, second call should give f(x), third call is f(x2) while x2 is the previous result of f(x) and so on..
what i have come up with:
def generate(f, x):
return itertools.repeat(lambda x: f(x))
which does not seem to work. any ideas? (i cant use yield in my code). also i cant use more than 1 line of code for this problem. any help would be appreciated.
also note that in a previous ex. i was asked to use the yield. with no problems:
while True:
yield x
x = f(x)
this works fine. but now.. no clue how to do it without
In Python 3.3, you can use itertools.accumulate:
import itertools
def generate(f, x):
return itertools.accumulate(itertools.repeat(x), lambda v,_:f(v))
for i, val in enumerate(generate(lambda x: 2*x, 3)):
print(val)
if i == 10:
break
I think this works:
import itertools as it
def g(f, x):
return it.chain([x],(setattr(g, 'x', f(getattr(g, 'x', x))) or getattr(g, 'x') for _ in it.count()))
def f(x):
return x + 1
gen = g(f, 1)
print next(gen)
print next(gen)
print next(gen)
print next(gen)
Of course, it relys on some sketchy behavior where I actually add an attribute to the function itself to keep the state. Basically, this function will only work the first time you call it. After that, all bets are off.
If we want to relax that restriction, we can use a temporary namespace. The problem is that to get a temporary namespace we need a unique class instance (or class, but an instance is cleaner and only requires 1 extra set of parenthesis). To make that happen in one line, we need to create a new function inline and use that as a default argument:
import itertools as it
def g(f, x):
return (lambda f, x, ns=type('foo', (object,), {})(): \
it.chain([x],
(setattr(ns, 'x', f(getattr(ns, 'x', x))) or getattr(ns, 'x')
for _ in it.count()))
)(f, x)
def f(x):
return x + 1
gen = g(f, 1)
print next(gen) == 1
print next(gen) == 2
print next(gen) == 3
print next(gen) == 4
print "first worked?"
gen2 = g(f, 2)
print next(gen2) == 2
print next(gen2) == 3
print next(gen2) == 4
I've broken it into a few lines, for readability, but it's a 1-liner at heart.
A version without any imports
(and the most robust one yet I believe).
def g(f, x):
return iter(lambda f=f, x=x, ns=type('foo', (object,), {'x':x}): ((getattr(ns, 'x'),setattr(ns, 'x', f(getattr(ns, 'x'))))[0]), object())
One trick here is the same as before. We create a lambda function with a mutable default argument to keep the state. Inside the function, we build a tuple. The first item is what we actually want, the second item is the return value of the setattr function which is used to update the state. In order to get rid of the itertools.chain, we set the initial value on the namespace to the value of x so the class is already initialzed to have the starting state. The second trick is that we use the two argument form of iter to get rid of it.count() which was only used to create an infinite iterable before. iter keeps calling the function you give it as the first argument until the return value is equal to the second argument. However, since my second argument is an instance of object, nothing returned from our function will ever be equal to it so we've effectively created an infinite iterable without itertools or yield! Come to think of it, I believe this last version is the most robust too. Previous versions had a bug where they relied on the truthfulness of the return value of f. I think they might have failed if f returned 0. This last version fixes that bug.
I'm guessing this is some sort of homework or assignment? As such, I'd say you should take a look at generator expressions. Though I agree with the other commenters that this seems an exercise of dubious value...

Is there a generally accepted pythonic syntax for modifying a generator's values?

Suppose I have a generator gen. Is there a more pythonic or simpler way of modifying gen's values than the example I have provided?
def genwrap(gen):
for value in gen:
yield(somefunc(value))
gen = somegenerator
for x in genwrap(gen):
print x
If it's actually applying a function that already exists, use map. Otherwise, this is fine, and can be shortened to a generator expression if it's simple enough (e.g. (x + 1 for x in somegenerator)).
def genwrap(gen):
return (somefunc(val) for val in gen)
The parentheses are not needed in the yield statement:
def genwrap(gen):
for value in gen:
yield somefunc(value)

Python functions within lists

So today in computer science I asked about using a function as a variable. For example, I can create a function, such as returnMe(i) and make an array that will be used to call it. Like h = [help,returnMe] and then I can say h1 and it would call returnMe("Bob"). Sorry I was a little excited about this. My question is is there a way of calling like h.append(def function) and define a function that only exists in the array?
EDIT:
Here Is some code that I wrote with this!
So I just finished an awesome FizzBuzz with this solution thank you so much again! Here's that code as an example:
funct = []
s = ""
def newFunct(str, num):
return (lambda x: str if(x%num==0) else "")
funct.append(newFunct("Fizz",3))
funct.append(newFunct("Buzz",5))
for x in range(1,101):
for oper in funct:
s += oper(x)
s += ":"+str(x)+"\n"
print s
You can create anonymous functions using the lambda keyword.
def func(x,keyword='bar'):
return (x,keyword)
is roughly equivalent to:
func = lambda x,keyword='bar':(x,keyword)
So, if you want to create a list with functions in it:
my_list = [lambda x:x**2,lambda x:x**3]
print my_list[0](2) #4
print my_list[1](2) #8
Not really in Python. As mgilson shows, you can do this with trivial functions, but they can only contain expressions, not statements, so are very limited (you can't assign to a variable, for example).
This is of course supported in other languages: in Javascript, for example, creating substantial anonymous functions and passing them around is a very idiomatic thing to do.
You can create the functions in the original scope, assign them to the array and then delete them from their original scope. Thus, you can indeed call them from the array but not as a local variable. I am not sure if this meets your requirements.
#! /usr/bin/python3.2
def a (x): print (x * 2)
def b (x): print (x ** 2)
l = [a, b]
del a
del b
l [0] (3) #works
l [1] (3) #works
a (3) #fails epicly
You can create a list of lambda functions to increment by every number from 0 to 9 like so:
increment = [(lambda arg: (lambda x: arg + x))(i) for i in range(10)]
increment[0](1) #returns 1
increment[9](10) #returns 19
Side Note:
I think it's also important to note that this (function pointers not lambdas) is somewhat like how python holds methods in most classes, except instead of a list, it's a dictionary with function names pointing to the functions. In many but not all cases instance.func(args) is equivalent to instance.__dict__['func'](args) or type(class).__dict__['func'](args)

How to test whether x is a member of a universal set?

I have a list L, and x in L evaluates to True if x is a member of L. What can I use instead of L in order x in smth will evaluate to True independently on the value of x?
So, I need something, what contains all objects, including itself, because x can also be this "smth".
class Universe:
def __contains__(_,x): return True
You can inherit from the built-in list class and redefine the __contains__ method that is called when you do tests like item in list:
>>> class my_list(list):
def __contains__(self, item):
return True
>>> L = my_list()
>>> L
[]
>>> x = 2
>>> x
2
>>> x in L
True
Theorem: There is no universal set.
Proof. Let X be a set such that X = {\empty, x} where x is every possible element in the domain. The question arises, is X \in X? Most sets are not defined that way, so let us define a new set Y. Y = {A \in X; A \notin A} i.e. Y is the set of all sets not belonging to themselves.
Now, does Y \in Y? Well, we have defined Y as all sets not belonging to themselves, so Y cannot exist in Y, which contradicts our assumption.
So now assume Y is not in Y. Now A definitely contains Y, as Y is not in itself, but the definition of Y is such that if we define Y to be in Y, we contradict our own definition.
Thus, there is no set of all sets. This is known as Russell's Paradox.
So, why programmatically try to create an object that violates a result proved and tested by set theorists far more intelligent than I am? If that was my interview, this would be my answer and if they insisted it was possible, I'd suggest explaining what the problem domain is, since conceptually Russell has fundamentally proved it is impossible.
If you want a user-friendly problem usually posed for people studying introductory set theory, try the Barber Paradox.
Edit: Python lets you implement an object that contains itself. See this:
class Universal(object):
def __init__(self):
self.contents = []
def add(self, x):
self.contents.append(x)
def remove(self, x):
self.contents.remove(x)
def __contains__(self, x):
return ( x in self.contents )
However, this is not a strict set theoretic object, since the contents actually contains a reference to the parent object. If you require that objects be distinct as per the proof above, this cannot happen.

Categories