What does fetch() fetch in GAE? - python

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

Related

Why the value of the parameter changed?

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)

Why the Python scope seems to behave differently for list variable and string variable?

Say that I have the following Python code:
import sys
class DogStr:
tricks = ''
def add_trick(self, trick):
self.tricks = trick
class DogList:
tricks = []
def add_trick(self, trick):
self.tricks.append(trick)
# Dealing with DogStr
d = DogStr()
e = DogStr()
d.add_trick('trick d')
e.add_trick('trick e')
print(d.tricks)
print(e.tricks)
# Dealing with DogList
d = DogList()
e = DogList()
d.add_trick('trick d')
e.add_trick('trick e')
print(d.tricks)
print(e.tricks)
Running this code with Python 3.6.5, I get the following output:
trick d
trick e
['trick d', 'trick e']
['trick d', 'trick e']
The difference between DogStr and DogList is that I treat tricks as a string on former and as a list on the latter.
When dealing with DogStr, tricks is behaving as an instance variable. BUT with DogList tricks is behaving as a class variable.
I was expecting to see the same behaviour on both calls, i.e.: if the two last lines of the output are identical, so should be the first two.
So I wonder. What is the explanation for that?
The difference is not int the type of the object, but in what your code does to it.
There is a big difference between these two:
self.tricks = trick
and:
self.tricks.append(trick)
The first one self.tricks = trick assigns a value to attribute tricks of self.
The second one self.tricks.append(trick) retrieves self.tricks and calls a method on it (which here modifies its values).
The problem, in your case, is that there is no tricks defined on self instance, so self.tricks.append gets the tricks attribute of the class and modifies it, but self.tricks = ... creates a new attribute on self instead.
The fact that one of them is a string and the other is a list is not really relevant. It would be the same if both were lists.
Note that they could not both be strings because strings are immutable and thus have no append method
How to fix it?
This is wrong:
def add_trick(self, trick):
self.tricks = trick
If tricks is a class attribute, add_trick should be a class method:
#classmethod
def add_trick(cls, trick):
cls.tricks = trick
If there are reasons for add_trick to be an instance method, then simply do this:
def add_trick(self, trick):
DogStr.tricks = trick

Python: Changing a single object within an array of objects changes all, even in a different array [duplicate]

This question already has an answer here:
Why does this code for initializing a list of lists apparently link the lists together? [duplicate]
(1 answer)
Closed 6 years ago.
I've got a one type of object, data_entry, that has a 2-dimensional array of other objects, time_entry.
Initialization of time_entries the array within data_entry looks like this:
[([time_entry()] * 12) for i in range(5)]
and initialization of the data_entry looks like this:
thing = data_entry()
Now, I have a list of "things", each which contains it's own 2d array of time_entrys.
Each time_entry has a list as one of it's attributes, initialized like so:
attributes = []
I modify attributes by extending it using .extend().
However, the problem I run into when I do this is EVERY single time_entry object in EVERY single data_entry object gets extended.
I know problems like this can arise from improper initialization of objects, so I'm wondering if perhaps my object creations are poor or there is another python quirk I am unaware of.
If you are performing the initialization on the class, it will affect all instances of the class. If that’s the case, this is not a result of it being in a list, but of it being on the class. For example:
#!/usr/bin/python
class BedrockDenizen():
attributes = []
wilma = BedrockDenizen()
fred = BedrockDenizen()
wilma.attributes.extend(['thin', 'smart'])
fred.attributes.extend(['fat', 'stupid'])
print 'Wilma:', wilma.attributes
print 'Fred:', fred.attributes
You will see that both Fred and Wilma are thin, smart, fat, and stupid.
Wilma: ['thin', 'smart', 'fat', 'stupid']
Fred: ['thin', 'smart', 'fat', 'stupid']
One way to fix this is to put the attribute creation into the init method, so that the attribute is per-instance:
class BedrockDenizen():
def __init__(self):
self.attributes = []
With that change, only Wilma is thin and smart, and only Fred is fat and stupid.
Wilma: ['thin', 'smart']
Fred: ['fat', 'stupid']
You may also need to show us more code. #Bakuriu notes that the problem may be that you are only creating one instance, and he may be right. For example, if this is closer to your code:
class BedrockDenizen():
def __init__(self):
self.attributes = []
neighborhood = [([BedrockDenizen()] * 2) for i in range(2)]
flintstones, rubbles = neighborhood
fred, wilma = flintstones
wilma.attributes.extend(['thin', 'smart'])
fred.attributes.extend(['fat', 'stupid'])
print 'Wilma:', wilma.attributes
print 'Fred:', fred.attributes
Then Fred and Wilma will continue to have the same attributes, because they aren’t really separate people. You may wish to use code more like this:
class BedrockDenizen():
def __init__(self):
self.attributes = []
neighborhood = [[BedrockDenizen() for n in range(2)] for i in range(2)]
flintstones, rubbles = neighborhood
fred, wilma = flintstones
wilma.attributes.extend(['thin', 'smart'])
fred.attributes.extend(['fat', 'stupid'])
print 'Wilma:', wilma.attributes
print 'Fred:', fred.attributes
That depends on what your needs are, though, as it seems like an odd way of doing things without more info.
This sounds like your attributes all point to the same list object inside. Then you call extend on the same object every time and modify it.
This is a common issue and discussed at
https://docs.python.org/3/faq/programming.html#how-do-i-create-a-multidimensional-list and Python list append behavior

Python 3.0 - Dynamic Class Instance Naming

I want to use a while loop to initialize class objects with a simple incremented naming convention. The goal is to be able to scale the number of class objects at will and have the program generate the names automatically. (ex. h1...h100...h1000...) Each h1,h2,h3... being its own instance.
Here is my first attempt... have been unable to find a good example.
class Korker(object):
def __init__(self,ident,roo):
self.ident = ident
self.roo = roo
b = 1
hwinit = 'h'
hwstart = 0
while b <= 10:
showit = 'h' + str(b)
print(showit) #showit seems to generate just fine as demonstrated by print
str(showit) == Korker("test",2) #this is the line that fails
b += 1
The errors I get range from a string error to a cannot use function type error.... Any help would be greatly appreciated.
If you want to generate a number of objects, why not simply put them in an array / hash where they can be looked up later on:
objects = {}
for b in range(1,11):
objects['h'+str(b)] = Korker("test", 2)
# then access like this:
objects['h3']
Of course there are ways to make the names available locally, but that's not a very good idea unless you know why you need it (via globals() and locals()).
Variables are names that point to objects that hold data. You are attempting to stick data into the variable names. That's the wrong way around.
instead of h1 to h1000, just call the variable h, and make it a list. Then you get h[0] to h[999].
Slightly different solution to viraptor's: use a list.
h = []
for i in range(10):
h.append(Korker("test",2))
In fact, you can even do it on one line with a list comprehension:
h = [Korker("test", 2) for i in range(10)]
Then you can get at them with h[0], h[1] etc.

Creating a list of objects in Python

I'm trying to create a Python script that opens several databases and compares their contents. In the process of creating that script, I've run into a problem in creating a list whose contents are objects that I've created.
I've simplified the program to its bare bones for this posting. First I create a new class, create a new instance of it, assign it an attribute and then write it to a list. Then I assign a new value to the instance and again write it to a list... and again and again...
Problem is, it's always the same object so I'm really just changing the base object. When I read the list, I get a repeat of the same object over and over.
So how do you write objects to a list within a loop?
Here's my simplified code
class SimpleClass(object):
pass
x = SimpleClass
# Then create an empty list
simpleList = []
#Then loop through from 0 to 3 adding an attribute to the instance 'x' of SimpleClass
for count in range(0,4):
# each iteration creates a slightly different attribute value, and then prints it to
# prove that step is working
# but the problem is, I'm always updating a reference to 'x' and what I want to add to
# simplelist is a new instance of x that contains the updated attribute
x.attr1= '*Bob* '* count
print "Loop Count: %s Attribute Value %s" % (count, x.attr1)
simpleList.append(x)
print '-'*20
# And here I print out each instance of the object stored in the list 'simpleList'
# and the problem surfaces. Every element of 'simpleList' contains the same attribute value
y = SimpleClass
print "Reading the attributes from the objects in the list"
for count in range(0,4):
y = simpleList[count]
print y.attr1
So how do I (append, extend, copy or whatever) the elements of simpleList so that each entry contains a different instance of the object instead of all pointing to the same one?
You demonstrate a fundamental misunderstanding.
You never created an instance of SimpleClass at all, because you didn't call it.
for count in xrange(4):
x = SimpleClass()
x.attr = count
simplelist.append(x)
Or, if you let the class take parameters, instead, you can use a list comprehension.
simplelist = [SimpleClass(count) for count in xrange(4)]
A list comprehension can be used to fill a list with separate instances of a class, like so:
instancelist = [MyClass() for i in range(29)]
This avoids the problem with multiplying a list of one element with *, which re-uses the same object.
It shouldn't be necessary to recreate the SimpleClass object each time, as some are suggesting, if you're simply using it to output data based on its attributes. However, you're not actually creating an instance of the class; you're simply creating a reference to the class object itself. Therefore, you're adding a reference to the same class attribute to the list (instead of instance attribute), over and over.
Instead of:
x = SimpleClass
you need:
x = SimpleClass()
Create a new instance each time, where each new instance has the correct state, rather than continually modifying the state of the same instance.
Alternately, store an explicitly-made copy of the object (using the hint at this page) at each step, rather than the original.
If I understand correctly your question, you ask a way to execute a deep copy of an object.
What about using copy.deepcopy?
import copy
x = SimpleClass()
for count in range(0,4):
y = copy.deepcopy(x)
(...)
y.attr1= '*Bob* '* count
A deepcopy is a recursive copy of the entire object. For more reference, you can have a look at the python documentation: https://docs.python.org/2/library/copy.html
I think this simply demonstrates what you are trying to achieve:
# coding: utf-8
class Class():
count = 0
names = []
def __init__(self,name):
self.number = Class.count
self.name = name
Class.count += 1
Class.names.append(name)
l=[]
l.append(Class("uno"))
l.append(Class("duo"))
print l
print l[0].number, l[0].name
print l[1].number, l[1].name
print Class.count, Class.names
Run the code above and you get:-
[<__main__.Class instance at 0x6311b2c>,
<__main__.Class instance at 0x63117ec>]
0 uno
1 duo
2 ['uno', 'duo']

Categories

Resources