Error when appending to python object lists - python

I have defined a series of python objects of class dofiles which have a name and some empty lists.
class dofile:
name = ""
lines = []
inputs = []
outputs = []
intermediates = []
I am using the following code to loop through a list of these dofile objects called dofiles (after I have run code which fills up the lines list for each object which I know works correctly). The problematic code detects the phrase using and the word after it, then should append the word to the inputs list for each object.
for dofile in dofiles:
for line in dofile.lines:
# using
using_tups = re.findall(r'(using)\s([^\s,]+)', line)
for tuple in using_tups:
dofile.inputs.append(tuple[1])
However, I am ending up with the word appended to the inputs list of all of the dofile objects in dofiles. (ex: print(dofiles[0].inputs) and print(dofiles[1].inputs) return the same thing although they scan different files).
Am I missing something about how objects, lists, or loops work in Python?
I've tried (dofile.inputs).append(tuple[1]) but it doesn't seem to make a difference.
Thanks.

You're creating static vars, variables that are consistent across all dofile class instances. Essentially what is going on is that instead of having an "inputs" list for all dofile instances, you have one list that each one points to. To make them specific to a single instance, initialize them inside the __init__ class:
class dofile:
def __init__(self):
self.name = ""
self.lines = []
self.inputs = []
self.outputs = []
self.intermediates = []

Related

Python: How to send list from one method back to another?

I hope I can describe this problem easily enough to be understood. My Python/CS education is not formal and I'm not always sure about my terminology. Bear with me and give me some grace, please.
I have a Class with at least two static methods. One method (A) calls the other (B) on a loop. Inside B, I append elements to a list if certain requirements are met. I want to share this list with the user (this is a command line tool). However, with how things are designed right now I am sharing the list one element on a time per loop. I am not sure how to populate this list fully and get it back to Method A and then share it with the user. If I make the list a constant outside of the methods then method B is unable to see it (??) and append to it. :(
helperclass.py
class HelperClass(object)
def __init__(self)
# { methods-n-code-here}
myclass.py
import helperclass
class MyClass(HelperClass)
#staticmethod
GenerateFoo(params1, params2, params3):
# generate some executable scripts
for x in projects:
# do stuff
MyClass.CreateBar(params1, params2, params3)
for y in other:
# do stuff
return xyz
#staticmethod
CreateBar(params1, params2, params3):
# do stuff
# do more stuff
myList = []
for x in list
if z.isThatThing():
ThatThing = click.confirm(# user prompt: Y/N)
# do this
if not ThatThing:
myList.append(foobar)
# more stuff
# more stuff
if len(myList) > 0:
for a in myList:
print(a)
Anyway, what is it that I do not understand? :(
All you need to do is add return myList at the end of CreateBar() function so that you can get back the list inside the for loop of GenerateFoo() function. And then if you want to concatenate the lists then you can declear a new empty list list = [] and then inside for loop of GenerateFoo() you can write myList = MyClass.CreateBar(params1, params2, params3) to store the list in myList and again to concatenate use list.extend(myList). At the end of GenerateFoo() return the concatenated list using return list.
I have edited your example code below and put ### to new and modified lines to make it easier to find them.
helperclass.py:
class HelperClass(object)
def __init__(self)
# { methods-n-code-here}
myclass.py
import helperclass
class MyClass(HelperClass)
#staticmethod
GenerateFoo(params1, params2, params3):
# generate some executable scripts
list = [] ###
for x in projects:
# do stuff
myList = MyClass.CreateBar(params1, params2, params3) ###
list.extend(myList) ###
for y in other:
# do stuff
return list ###
#staticmethod
CreateBar(params1, params2, params3):
# do stuff
# do more stuff
myList = []
for x in list
if z.isThatThing():
ThatThing = click.confirm(# user prompt: Y/N)
# do this
if not ThatThing:
myList.append(foobar)
return myList ###

Creating and declaring list in class

I am trying to create a list within a class and then declaring elements in that list.
I don't even know if this is the right way for python. I have some java background.
I didn't add 10 elements in the list manually because I feel creating a dynamic list will be more useful.
class Levels:
def __init__(self):
self.type = "A"
self.size = [] # trying to create a list for 10 elements.
self.makespace(self.size) # running this method to create 10 spaces and then declare them.
def makespace(self, size):
for i in range(0,10):
if(size[i] == None):
size[i] = "free"
print(i)
else:
print("Didn't work")
print(i)
test = Levels()
Your problem lies in here.
if(size[i] == None):
size[i] = "free"
print(i)
At this moment, size is empty, it doesn't contain any elements so why are you
checking size[i] == None?
You probably think that a python list behaves like an array in Java where it initializes everything with null? Even though here you are not declaring the size of the list inside the init constructor, so I'm curious how you thought of that.
Your code should look like this:
class Levels:
def __init__(self):
self.type = "A"
self.size = [] # trying to create a list for 10 elements.
self.makespace(self.size) # running this method to create 10 spaces and then declare them.
def makespace(self, size):
#This will fill the emty list with 10 None(null) values
for i in range(0,10):
size.append(None)
test = Levels()
Also a bonus:
class Levels:
def __init__(self):
self.type = "A"
self.size = []
#Notice that I'm not passing self as an argument when I call makespace()
self.makespace()
def makespace(self):
#This will fill the emty list with 10 None(null) values
for i in range(0,10):
self.size.append(None)
test = Levels()
Self is the this keyword in python, the difference is that in Python you need to pass it as an argument only when declaring methods, not when you call them and also you can name it whatever you want!
Hope this helps!
This code won't work because size[i] does not exist. Instead use size.append(...). Also you should pass a number to makespace so that you can make space for an arbitrary number of items.
class Levels:
def __init__(self, kind='A', size=10):
self.kind = kind
self.size = [ 0 for _ in range(10) ]
These slight changes make your code more robust and more pythonic.
First but the least important is that type is a builtin-method (also a class and also a type) so kind is often substituted.
Second You can pass default arguments to the constructor (or any function) as you should generally avoid having constants inside functions like that. Here you can arbitrarily set a Level's kind, as well as the initial space required.
Third Using list-comprehension you can create a list of arbitrary size (or elements). The syntax is
[ expression for args in iterable ]
which allows for any expression to be generated based on arguments passed from an iterable. Read more about list comprehension and other datastructure here.
As for your makespace you shouldnt really need it, however you could change the implementation so you can allocate more space (using self.size.append(...)) or overwriting currently used space.
Best of luck!
If you want to have 10 free spaces in the list upon initializing, change
self.size = []
to
self.size = [“free”] * 10
If you want to start with an empty list and add 10 free spaces in your makespace loop, simply use
self.size.append(“free”)
Also, you really don’t need to pass size to makespace. Since you’re already passing self, I would just reference self.size from inside the makespace function.

Python: Copy two dependent lists together with their dependence

I am stuck with some problem which I guess is not very difficult, but I could not find any answer to it.
I have two lists of objects, each of them containing lists of objects in the other. I would like to copy them both to do come tests and evaluate the results before repeating the process. In the end, I would keep the best result.
However, when copying each lists, the result is, unsurprisingly, not two dependent lists but two lists which do not interact anymore. How can I solve this? Is there some proper way to do it?
Given the two classes defined as follow.
import copy
class event:
def __init__(self, name):
self.name = name
self.list_of_persons = []
def invite_someone(self, person):
self.list_of_persons.append(person)
person.list_of_events.append(self)
class person:
def __init__(self, name):
self.name = name
self.list_of_events = []
I tried to write some simple example of the situation I am facing. The print function shows that the objects identifiers are different in the two lists.
# Create lists of the events and the persons
the_events = [event("a"), event("b")]
the_persons = [person("x"), person("y"), person("z")]
# Add some persons at the events
the_events[0].invite_someone(the_persons[0])
the_events[0].invite_someone(the_persons[1])
the_events[1].invite_someone(the_persons[1])
the_events[1].invite_someone(the_persons[2])
print("Original :", id(the_persons[1]), id(the_events[0].list_of_persons[1]), id(the_events[1].list_of_persons[0]))
# Save the original configuration
original_of_the_events = copy.deepcopy(the_events)
original_of_the_persons = copy.deepcopy(the_persons)
for i in range(10):
# QUESTION: How to make the following copies?
the_events = copy.deepcopy(original_of_the_events)
the_persons = copy.deepcopy(original_of_the_persons)
print(" i =", i, ":", id(the_persons[1]), id(the_events[0].list_of_persons[1]), id(the_events[1].list_of_persons[0]))
# Do some random stuff with the two lists
# Rate the resulting lists
# Record the best configuration
# Save the best result in a file
I thought about using some dictionary and make the list independent, but that would imply a lot of code revision which I would like to avoid.
Thank you in advance for any help! I am new both to Python and StackExchange.
Since deepcopy makes copies of all underlying objects of the thing being copied, doing two independent calls to deepcopy breaks your links between objects. If you create a new object with references to both of these things (like a dict) and copy that object, that will preserve the object references.
workspace = {'the_persons': the_persons, 'the_events': the_events}
cpw = copy.deepcopy(workspace)

Store and Retrieve Objects from Python Lists

I am new to python and have a difficulty getting an object to be stored and access in an array or a list in Python.
I've tried doing something like this:
class NodeInfo:
def __init__(self, left, value, right):
self.l = left
self.r = right
self.v = value
tree[0] = NodeInfo(0,1,2)
tree[0].l = 5
tree[0].r = 6
tree[0].v = 7
When I try to assign values to or try to read from the variable, I get the following error:
tree[0] = NodeInfo(0,1,2)
NameError: name 'tree' is not defined
What am I doing wrong, or is there a different way to assign and read objects from arrays or lists in Python.
You need to create list first and use append method to add an element to the end of it.
tree = []
tree.append(NodeInfo(0,1,2))
# or
tree = [NodeInfo(0,1,2)]

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