This is my code:
def getGraphWave(G, d, maxk, p):
data = dict()
output_wavelets = {2:33,5:77,...}
print(len(output_wavelets))
k = [10,20]
for i in k:
S = graphwave(i, output_wavelets)
# size = avgSize(G, S, p, 200)
size = IC(d, S, p)
data[i] = size + i
return data
The output_wavelets is a dict and the length of it is 2000.
However, when running the following code:
def graphwave(k, output_wavelets):
S = []
print(len(output_wavelets))
for i in range(k):
Seed = max(output_wavelets, key=output_wavelets.get)
S.append(Seed)
output_wavelets.pop(Seed)
return S
In the getGraphWave(G,D,maxk,p), graphWave(k,output_wavelets) runs two times in the circulation. However, Why in the graphWave(), the result of print(len(output_wavelets)) is 2000 and 1991?
I thought output_wavelets is not changed before output_wavelets. And how to let output_wavelets always be the original?
When you call graphwave(i, output_wavelets) this passes a reference to output_wavelets into the function, not a copy of output_wavelets. This means that when the function modifies the output_wavelets dictionary it is modifying the original dictionary.
The output_wavelets.pop(Seed) line removes items from the dictionary, so is modifying the output_wavelets dictionary that you passed in. That is why it is getting smaller!
There are various ways which you could fix this. The simplest (but probably not the most efficient) would be to use the copy.copy() function to make a copy of your dictionary at the start of the graphwave function, and edit the copy rather than the original.
First you need to understand how value pass in python. Actually it depend on param which you passing to function.
like if you pass list, dict or any mutable object.. it can modify within the function.
but if you pass tuple, string or any immutable object.. it will not change.
In your case you can copy existing dict and then modify it. like
temp_output_wavelets = copy.deepcopy(output_wavelets)
Related
I was checking the code of the toolz library's groupby function in Python and I found this:
def groupby(key, seq):
""" Group a collection by a key function
"""
if not callable(key):
key = getter(key)
d = collections.defaultdict(lambda: [].append)
for item in seq:
d[key(item)](item)
rv = {}
for k, v in d.items():
rv[k] = v.__self__
return rv
Is there any reason to use rv[k] = v.__self__ instead of rv[k] = v?
This is a somewhat confusing trick to save a small amount of time:
We are creating a defaultdict with a factory function that returns a bound append method of a new list instance with [].append. Then we can just do d[key(item)](item) instead of d[key(item)].append(item) like we would have if we create a defaultdict that contains lists. If we don't lookup append everytime, we gain a small amount of time.
But now the dict contains bound methods instead of the lists, so we have to get the original list instance back via __self__.
__self__ is an attribute described for instance methods that returns the original instance. You can verify that with this for example:
>>> a = []
>>> a.append.__self__ is a
True
This is a somewhat convoluted, but possibly more efficient approach to creating and using a defaultdict of lists.
First, remember that the default item is lambda: [].append. This means create a new list, and store a bound append method in the dictionary. This saves you a method bind on every further append to the same key, and the garbage collect that follows. For example, the following more standard approach is less efficient:
d = collections.defaultdict(list)
for item in seq:
d[key(item)].append(item)
The problem then becomes how to get the original lists back out of the dictionary, since the reference is not stored explicitly. Luckily, bound methods have a __self__ attribute which does just that. Here, [].append.__self__ is a reference to the original [].
As a side note, the last loop could be a comprehension:
return {k: v.__self__ for k, v in d.items()}
I'm working on getting a better grasp of Python 3 fundamentals, specifically objects and modifying them in the context of a list (for now).
I created a simple class called MyThing() that just has a number, letter, and instance method for incrementing the number. My goal with this program was to create a list of 3 "MyThings", and manipulate the list in various ways. To start, I iterated through the list (obj_list_1) and incremented each number using each object's instance method. Easy enough.
What I'm trying to figure out how to do is perform the same operation in one line using the map function and lambda expressions (obj_list_2).
#!/usr/bin/env py
import copy
class MyThing:
def __init__(self, letter='A', number=0):
self.number = number
self.letter = letter
def __repr__(self) -> str:
return("(letter={}, number={})".format(self.letter, self.number))
def incr_number(self, incr=0):
self.number += incr
# Test program to try different ways of manipulating lists
def main():
obj1 = MyThing('A', 1)
obj2 = MyThing('B', 2)
obj3 = MyThing('C', 3)
obj_list_1 = [obj1, obj2, obj3]
obj_list_2 = copy.deepcopy(obj_list_1)
# Show the original list
print("Original List: {}".format(obj_list_1))
# output: [(letter=A, number=1), (letter=B, number=2), (letter=C, number=3)]
# Standard iterating over a list and incrementing each object's number.
for obj in obj_list_1:
obj.incr_number(1)
print("For loop over List, adding one to each number:\n{}".format(obj_list_1))
# output: [(letter=A, number=2), (letter=B, number=3), (letter=C, number=4)]
# Try using map function with lambda
obj_list_2 = list(map(lambda x: x.incr_number(1), obj_list_2))
print("Using maps with incr_number instance method:\n{}".format(obj_list_2))
# actual output: [None, None, None] <--- If I don't re-assign obj_list_2...it shows the proper sequence
# expected output: [(letter=A, number=2), (letter=B, number=3), (letter=C, number=4)]
if __name__ == "__main__":
main()
What I can't figure out is how to get map() to return the correct type, a list of "MyThing"s.
I understand that between Python 2 and Python 3, map changed to return an iterable instead of a list, so I made sure to cast the output. What I get is a list of 'None' objects.
What I noticed, though, is that if I don't re-assign obj_list_2, and instead just call list(map(lambda x: x.incr_number(1), obj_list_2)), then print obj_list_2 in the next line, the numbers get updated as I expect.
However, if I don't cast the map iterable and just do map(lambda x: x.incr_number(1), obj_list_2), the following print statement shows the list as having not been updated. I read in some documentation that the map function is lazy and doesn't operate until it's use by something...so this makes sense.
Is there a way that I can get the output of list(map(lambda x: x.incr_number(1), obj_list_2)) to actually return my list of objects?
Are there any other cool one-liner solutions for updating a list of objects with their instance methods that I'm not thinking of?
TL;DR: Just use the for-loop. There's no advantage to using a map in this case.
Firstly:
You're getting a list of Nones because the mapped function returns None. That is, MyThing.incr_number() doesn't return anything, so it returns None implicitly.
Fewer lines is not necessarily better. Two simple lines are often easier to read than one complex line.
Notice that you're not creating a new list in the for-loop, you're only modifying the elements of the existing list.
list(map(lambda)) is longer and harder to read than a list comprehension:
[x.incr_number(1) for x in obj_list_2]
vs
list(map(lambda x: x.incr_number(1), obj_list_2))
Now, take a look at Is it Pythonic to use list comprehensions for just side effects? The top answer says no, it creates a list that never gets used. So there's your answer: just use the for-loop instead.
This is because, your incr_number doesn't return anything. Change it to:
def incr_number(self, incr=0):
self.number += incr
return self
The loop is clearly better, but here's another way anyway. Your incr_number doesn't return anything, or rather returns the default None. Which is a false value, so if you simply append or x, then you do get the modified value instead of the None
Change
list(map(lambda x: x.incr_number(1), obj_list_2))
to this:
list(map(lambda x: x.incr_number(1) or x, obj_list_2))
Say we have a function in a file, something like:
..... other fucntions
def add_to_list(l = []):
l.append("foo")
..... other functions
When will def be called? What exactly does def do?
[] creates a list and, for efficiency reasons, when a list is passed, it isn't duplicated or passed by value; it is sent by reference. A similar thing is happening with this. So, firstly all def's are initialized by Python. Then your code is run. However, the initializer has already created the list.
>>> id(add_to_list())
12516768
>>> id(add_to_list())
12516768
>>> id(add_to_list())
12516768
Excerpt from http://effbot.org/zone/default-values.htm
Notice how they have the same id? That's because it's returning the same instance of list every time. Thus, l = [] isn't creating a new instance at run time. So, we keep on appending to the same instance.
That is why we don't experience this behavior with ints, floats, and etc.
Consider your code:
def add_to_list(l = []):
l.append("foo")
print(l)
add_to_list()
add_to_list()
Then it's output:
['foo']
['foo', 'foo']
Now consider this similar function:
def add_to_list():
l = []
l.append("foo")
print(l)
add_to_list()
add_to_list()
The output will be:
['foo']
['foo']
That's because the l = [] is run after the constructors are initialized (in live time). When you consider the first code, you will see that the constructor is ran first, then the code executes live time.
def is executed whenever you hit it in parsing the source file. It defines the function. This means that the body of the function is assigned to the name, the parameters are included in the "signature" (calling format), etc. IN other words, the function is now ready to call from anywhere below that point, within the scope of the containing program.
Since l is a list, it's bound to whatever you pass into the function call. If you pass in a list, then it's bound by reference to that list, a mutable object.
As to your specific case, there's really no use case that will make sense: since you have to pass an object with an append method, anything you supply will have a value: it will never use the default value. The only way to get that default value into play is to call with empty parentheses, in which case there's no way to get the value back to the calling program (since you return nothing).
Thus, when you call the routine a second time, it appears that you're using the same list you passed the first time. That list already has the "foo" element you added that first time. Here's some test code and the output to illustrate the effect:
def add_to_list(l = []):
l.append("foo")
print "l =", l
empty = []
add_to_list(empty)
print "empty #1", empty
add_to_list(empty)
print "empty #2", empty
add_to_list()
Output:
l = ['foo']
empty #1 ['foo']
l = ['foo', 'foo']
empty #2 ['foo', 'foo']
l = ['foo']
Does that clarify things?
I have python 3 code that is not working as expected:
def addFunc(x,y):
print (x+y)
def subABC(x,y,z):
print (x-y-z)
def doublePower(base,exp):
print(2*base**exp)
def RootFunc(inputDict):
for k,v in inputDict.items():
if v[0]==1:
d[k] = addFunc(*v[1:])
elif v[0] ==2:
d[k] = subABC(*v[1:])
elif v[0]==3:
d[k] = doublePower(*v[1:])
d={"s1_7":[1,5,2],"d1_6":[2,12,3,3],"e1_3200":[3,40,2],"s2_13":[1,6,7],"d2_30":[2,42,2,10]}
RootFunc(d)
#test to make sure key var assignment works
print(d)
I get:
{'d2_30': None, 's2_13': None, 's1_7': None, 'e1_3200': None, 'd1_6': None}
I expected:
{'d2_30': 30, 's2_13': 13, 's1_7': 7, 'e1_3200': 3200, 'd1_6': 6}
What's wrong?
Semi related: I know dictionaries are unordered but is there any reason why python picked this order? Does it run the keys through a randomizer?
print does not return a value. It returns None, so every time you call your functions, they're printing to standard output and returning None. Try changing all print statements to return like so:
def addFunc(x,y):
return x+y
This will give the value x+y back to whatever called the function.
Another problem with your code (unless you meant to do this) is that you define a dictionary d and then when you define your function, you are working on this dictionary d and not the dictionary that is 'input':
def RootFunc(inputDict):
for k,v in inputDict.items():
if v[0]==1:
d[k] = addFunc(*v[1:])
Are you planning to always change d and not the dictionary that you are iterating over, inputDict?
There may be other issues as well (accepting a variable number of arguments within your functions, for instance), but it's good to address one problem at a time.
Additional Notes on Functions:
Here's some sort-of pseudocode that attempts to convey how functions are often used:
def sample_function(some_data):
modified_data = []
for element in some_data:
do some processing
add processed crap to modified_data
return modified_data
Functions are considered 'black box', which means you structure them so that you can dump some data into them and they always do the same stuff and you can call them over and over again. They will either return values or yield values or update some value or attribute or something (the latter are called 'side effects'). For the moment, just pay attention to the return statement.
Another interesting thing is that functions have 'scope' which means that when I just defined it with a fake-name for the argument, I don't actually have to have a variable called "some_data". I can pass whatever I want to the function, but inside the function I can refer to the fake name and create other variables that really only matter within the context of the function.
Now, if we run my function above, it will go ahead and process the data:
sample_function(my_data_set)
But this is often kind of pointless because the function is supposed to return something and I didn't do anything with what it returned. What I should do is assign the value of the function and its arguments to some container so I can keep the processed information.
my_modified_data = sample_function(my_data_set)
This is a really common way to use functions and you'll probably see it again.
One Simple Way to Approach Your Problem:
Taking all this into consideration, here is one way to solve your problem that comes from a really common programming paradigm:
def RootFunc(inputDict):
temp_dict = {}
for k,v in inputDict.items():
if v[0]==1:
temp_dict[k] = addFunc(*v[1:])
elif v[0] ==2:
temp_dict[k] = subABC(*v[1:])
elif v[0]==3:
temp_dict[k] = doublePower(*v[1:])
return temp_dict
inputDict={"s1_7":[1,5,2],"d1_6":[2,12,3,3],"e1_3200":[3,40,2],"s2_13":[1,6,7],"d2_30"[2,42,2,10]}
final_dict = RootFunc(inputDict)
As erewok stated, you are using "print" and not "return" which may be the source of your error. And as far as the ordering is concerned, you already know that dictionaries are unordered, according to python doc at least, the ordering is not random, but rather implemented as hash tables.
Excerpt from the python doc: [...]A mapping object maps hashable values to arbitrary objects. Mappings are mutable objects. There is currently only one standard mapping type, the dictionary. [...]
Now key here is that the order of the element is not really random. I have often noticed that the order stays the same no matter how I construct a dictionary on some values... using lambda or just creating it outright, the order has always remained the same, so it can't be random, but it's definitely arbitrary.
This is a follow up to my other question.
I thought that
mylist = list(Rep().all().fetch(50))
makes mylist a list. But when I try to get its length I get the message
self.response.out.write(len(P))
TypeError: object of type 'Rep' has no len()
Can anyone explain what I am doing wrong?
Rep().replist = L
Rep().put()
mylist = list(Rep().all().fetch(50))
P = mylist.pop()
self.response.out.write(len(P))
UPDATE
As a reference for others who may encounter the same problem; I post the following table which was very helpful to me. (The original here)
Rep().........................Rep object
Rep.all().....................Query object
list(Rep.all())...............List of Rep objects.
list(Rep.all())[0]............A single Rep object
list(Rep.all())[0].replist....A list
Thanks for all the answers.
Instead of this:
Rep().replist = L
Rep().put()
mylist = list(Rep().all().fetch(50))
P = mylist.pop()
self.response.out.write(len(P))
Try something like this:
r = Rep()
r.replist = L
r.put()
mylist = Rep.all().fetch(50)
P = mylist.pop()
self.response.out.write(len(P.replist))
This code of yours:
Rep().replist = L
Rep().put()
Is creating a Rep instance, then assigning its replist to L. Then it's creating another Rep, and calling put() on it. So the one you are writing to the datastore is a blank Rep - it won't have your list.
In this code:
mylist = list(Rep().all().fetch(50))
You are calling all() on an instance of Rep - you should instead call it directly on the class. Also you don't need to wrap the results in list(), as fetch() already returns a list.
Then below where you have this:
self.response.out.write(len(P))
You are trying to get the length of P (which is a Rep), not the length of P's replist.
Update:
In response to the first comment:
In this code:
r = Rep()
The Rep() is creating an instance of a Rep. The r = is then assigning that instance to the name r. So now the name r refers to that instance of a Rep.
Then in this code:
r.replist = L
It is assigning the replist property of r to refer to the list L.
You are correct, instead of those two lines you can do this:
r = Rep(replist = L)
What this does is pass L to the __init__ function of Rep, with the argument name replist. The __init__ function of Rep is inherited from the db.Model base class. This function assigns the value of any arguments provided to a property of the same name on the model. So in this case, it assigns L to the replist property. So it has the same effect as the original two lines of code, but it works a bit differently.
In response to the second comment:
The = operator in Python means assignment, which is not the same as mathematical equivalence.
So this code:
r = Rep()
Does not mean that r is now equivalent to Rep(), and that you can now use r and Rep() to mean the same thing.
What it means is that r is now equal to the result of Rep(). What Rep() does is allocate a new instance of a Rep. So that makes r a reference to a new Rep. To refer to that same instance later, you therefore need to use r, not Rep() (which would allocate a new instance each time you call it).
if you want to print the number of elements of replist property.
self.response.write(len(P.replist));
Hope i can help you :p
Try this:
self.response.out.write(len(mylist))