Python 3.5 handling lists strangely [duplicate] - python

This question already has answers here:
python class instance variables and class variables
(4 answers)
Closed 5 years ago.
I came across some rather strange behavior.
class Example:
test = []
def __init__(self):
print(self.test)
self.test.append(0)
ex1 = Example()
ex2 = Example()
ex3 = Example()
I'd expect this to output [] every time, however, I get:
[]
[0]
[0, 0]
What is this wizardry? Could you help me understand?
Thank, you!
Edit:
Hey, thank you for the quick answers.
Just to clarify, if "test" is static then why do I not notice this behavior when I replace "self.test.append(0)" with "self.test = [0]"?

test is a static class attribute, which you are continually updating with values. Python is different from some other languages in this way. To make it an object attribute, use self.test = [] in your constructor.

test there is a class-level static variable, which is shared between the instances of the class.
You'll want to initialize test within the __init__ method.
class Example:
def __init__(self):
self.test = []
print(self.test)
self.test.append(0)

Related

How to dynamically create instance of a class automatically in python [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 2 years ago.
I have a class and I want to create dynamically instances of that class. I don't know the exact number of instances so that I dont want to create that classes by a known variable like this:
class Person:
def __init__(self, age, gender):
self.age=age
self.gender=gender
P1=Person(23, "M")
P2=Person(64, "F")
P3=Person(12, "M")
I am looking for sth like
i=0
maxPopulation=10
while i< maxPopulation:
Person(randomx, randomy)
i+=1
But that way I don't know how to access the instances. During the runtime.
I am not looking for a random function.
Add them to a list.
i=0
maxPopulation=10
people = []
while i< maxPopulation:
people.append(Person(randomx, randomy))
i+=1
Or, cleaned up a bit to be more Pythonic:
maxPopulation=10
people = []
for _ in range(maxPopulation):
people.append(Person(randomx, randomy))
Or even more Pythonic:
max_population = 10
people = [Person(randomx, randomy) for _ in range(max_population)]

Why are attributes in different objects connected to each other when a default argument is given? [duplicate]

This question already has answers here:
"Least Astonishment" and the Mutable Default Argument
(33 answers)
Closed 3 years ago.
I am implementing a basic node object in python. Basically, I implemented a node class with the attribute f_pointers and set it to the default value []. When ever I try to change f_pointers of (lets say) node_a, I will end up changing f_pointers of node_b, which are programmed to be completely unrelated.
I have already solved the problem by instead changing the default value to None and setting up the forward_pointers in __init__. However, I would still like to know how to avoid this problem in the future and possibly learn something new about Python.
For the sake of simplicity, I removed some unnecessary parts of the code.
class Node:
def __init__(self, f_pointers = []):
self.f_pointers = f_pointers
def get_pointers(self):
return self.f_pointers
def add_pointers(self, new_pointer):
self.f_pointers.append(new_pointer)
a = Node()
b = Node()
print(a.get_pointers, b.get_pointers)
>>> [] []
a.add_pointers("a")
print(a.get_pointers, b.get_pointers)
>> ["a"] ["a"]
a.add_pointers("b")
print(a.get_pointers, b.get_pointers)
>> ["a","b"] ["a","b"]
As can be seen, a and b are completely unrelated objects (other than the fact that they are of the same type Node) but will affect each other. Why does this happen?
It's because you are referencing to the same list (the one instantiated in the __init__ default params list definition like __init__(self, f_pointers=[]). What happens is that when you say in the __init__ method code block that self.f_points = f_pointers you are basically referencing the same list every time you instantiate a new Node object.
The reasons are explained further here
What you do want to do instead is instantiate a new list for every init like:
def __init__(self, f_pointers=None):
self.f_pointers = []
You should do it like this.
class Node:
def __init__(self, f_pointers=None):
if f_pointers:
self.f_pointers = f_pointers
else:
self.f_pointers = []
def get_pointers(self):
return self.f_pointers
def add_pointers(self, new_pointer):
self.f_pointers.append(new_pointer)
a = Node()
b = Node()
print(a.get_pointers(), b.get_pointers())
a.add_pointers("a")
print(a.get_pointers(), b.get_pointers())
You get this kind of behavior because in your case a.f_pointers and b.f_pointers is the same list, which was generated, when you described your class Node.
So a.f_pointers is b.f_pointers == True in your case

Defining attributes of a class in Python [duplicate]

This question already has answers here:
How should I choose between using instance vs. class attributes?
(4 answers)
Closed 8 years ago.
How should I define the attributes of a class?
class Example:
def __init__(self,n,m):
self.n=n
self.m=m
or in this way:
class Example:
m=0
n=0
def __init__(self,n,m):
self.n=n
self.m=m
If I define an attribute outside the constructor, is it a static variable?
I think you are confusing instance variables and variables of the class itself (you could call them static if you are coming from java). Have a look at this demo (note that __init__ needs two underscores).
class Example:
m=0
n=0
def __init__(self,n,m):
self.n=n
self.m=m
e = Example(1,2)
print(e.m) # 2
print(e.n) # 1
print(Example.m) # 0
print(Example.n) # 0
In your second code, Example has the class variables m and n, and each instance of an Example object will have instance members self.m and self.n.
This way:
class Example:
def __init__(self,n,m):
self.n=n
self.m=m
Double score the init, like this: __init__, not like this _init_!
m=0 and n=0 are class attributes, and don't have anything with self.n and self.m, which are instance variables.

Python... Static variables? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Instance variables vs. class variables in Python
What is the difference between these two situations and how is it treated with in Python?
Ex1
class MyClass:
anArray = {}
Ex2
class MyClass:
__init__(self):
self.anArray = {}
It seems like the in the first example the array is being treated like a static variable. How does Python treat this and what is the reason for this?
In the first example, anArray (which in Python is called a dictionary, not an array) is a class attribute. It can be accessed using MyClass.anArray. It exists as soon as the class is defined.
In the second example, anArray is an instance attribute. It can be accessed using MyClass().anArray. (But note that doing that just throws away the MyClass instance created; a more sensible example is mc = MyClass(); mc.anArray['a'] = 5.) It doesn't exist until an instance of the class is created.
It is declared diffrent area.
Ex1 is Like global or static variable.
obj = MyClass()
obj2 = MyClass()
print "IS one instance ", id(obj.anArray) == id(obj2.anArray)
Ex2 is local attribute.
obj = MyClass()
obj2 = MyClass()
print "IS one instance ", id(obj.anArray) == id(obj2.anArray)

List in a Python class shares the same object over 2 different instances? [duplicate]

This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 15 days ago.
I created a class:
class A:
aList = []
now I have function that instantiate this class and add items into the aList.
note: there are 2 items
for item in items:
a = A();
a.aList.append(item);
I find that the first A and the second A object has the same number of items in their aList.
I would expect that the first A object will have the first item in its list and the second A object will have the second item in its aList.
Can anyone explain how this happens ?
PS:
I manage to solve this problem by moving the aList inside a constructor :
def __init__(self):
self.aList = [];
but I am still curious about this behavior
You have defined the list as a class attribute.
Class attributes are shared by all instances of your class.
When you define the list in __init__ as self.aList, then the list is an attribute of your instance (self) and then everything works as you expected.
You are confusing class and object variables.
If you want objects:
class A(object):
def __init__(self):
self.aList = []
in your example aList is a class variable, you can compare it with using the 'static' keyword in other languages. The class variable of course is shared over all instances.
This happened because list is a mutable object, and it is created once only when defining the class, that is why it becomes shared when you create two instances. Eg,
class A:
a = 0 #immutable
b = [0] #mutable
a = A()
a.a = 1
a.b[0] = 1
b = A()
print b.a #print 0
print b.b[0] #print 1, affected by object "a"
Therefore, to solve the problem, we can use constructor like what you have mentioned. When we put the list in constructor, whenever the object is instantiated, the new list will also be created.
In Python, variables declared inside the class definition, instead of inside a method, are class or static variables. You may be interested in taking a look at this answer to another question.

Categories

Resources