I am struggling to understand why instance C keeps data of instance B, even though I initialized the instance variable var with the default empty list. Why is the default argument "var = []" ignored?.
class A():
def __init__(self, var=[]):
self.var = var
B = A()
B.var.append(3)
C = A()
print(C.var)
The print retuns
[3]
Even stranger is this:
class A():
def __init__(self, var=[2]):
self.var = var
B = A()
B.var.append(3)
C = A()
print(C.var)
prints
[2, 3]
How can the statement self.var = var append to the list from the front?
According to what's given here
A Python variable is a symbolic name that is a reference or pointer to an object. Once an object is assigned to a variable, you can refer to the object by that name. But the data itself is still contained within the object.
B = A()
B.var.append(3)
Here, A's reference is passed to B. So they point to the same data, but are just called by different names. So whatever operation you perform on B, you also perform on A.
Hence, later when you assign A to C, the same data is referenced by C.
If you don't want that to happen, use deepcopy:
class A():
def __init__(self, var=[]):
self.var = var
import copy
B = copy.deepcopy(A())
B.var.append(3)
C = A()
print(C.var)
Related
Do constructors initialize attributes for a specific object at the time of object creation?
I created a simple class for addition.
I used constructor and initialized two parameters a and b.
Now I created an add method in that class. For which I used same letters a and b.
Now when I create an object, like
Object = class(a-value, b-value)
Print(object.add())
I was expecting that initialized a and b values to be sent to add method.
But error is still asking me to pass the positional arguments for add()
And when I print(object.a) - I get the initialized value for a!
So is constructor used for passing attributes for that specific object?
While add function needs parameters and arguments for those parameters?
Full Code(from comment):
class Addition:
def __init__(self, a, b):
self.a = a
self.b = b
def addition(self, a, b):
add=a+b
return add
object1 = Addition(20, 30)
print(object1.addition())
You're including local arguments when you don't need to.
Simply removing them and referring to the instance variables(attributes) will fix your problem.
class Addition:
def __init__(self, a, b):
self.a = a
self.b = b
def addition(self):
add = self.a + self.b
return add
object1 = Addition(20, 30)
print(object1.addition())
Python is very helpful when you create an object and implicitly passes the instance as the first argument to a bound method.
For this reason, we need to always include an argument in our methods that the instance can be handed to.
The standard name for this argument is self (although it can be anything) it is helpful to readers of your code to refer it to as everyone else does.
So calling object1.addition() is essentially doing this on a normal unbound function.
def normal_func_addition(some_object):
add = some_object.a + some_object.b
return add
object1 = Addition(20, 30)
print(normal_func_addition(object1))
Your other question was "Why need a constructor at all?"
The answer to this is it's a good place to set our attributes on the object.
Again, we could achieve this with a simple top level function.
def func_init(some_object, a, b):
some_object.a = a
some_object.b = b
class Addition:
pass
object1 = Addition()
func_init(object1, 20, 30)
print(object1.a)
print(object1.b)
or even directly.
object1.a = 20
object1.b = 30
But that's a lot of boilerplate and it's nice to do it all in one step.
So in essence, object1 = Addition(20, 30) creates an Addition object (object1) and hands that object to __init__ along with 20 and 30.
There you assign the attributes .a and .b to it. Then when you call object1.addition() it again hands the instance (object1) to it. There you can pull the attributes back out that you assigned in __init__.
Is this helpful?
class Test():
def __init__(self, a, b):
self.a = a
self.b = b
def add(self):
return self.a + self.b
test = Test(15, 10)
print(test.a)
print(test.b)
print(test.add())
I currently have a class with a few attributes. Each of those attributes has their own methods. The structure looks as follows.
class A(object):
def __init__(self,B,C):
self.attribute_B = B
self.attribute_C = C
class B():
def foo(self):
#Very relevant and important code
A.attribute_C = None
return result
This is a simplified version of the structure. What I would like to know is how to modify attribute_C from inside the function body of attribute_B like follows.
beta = B()
charlie = C()
alpha = A(beta,charlie)
print(alpha.attribute_C) # prints C
alpha.attribute_B.foo()
print(alpha.attribute_C) # prints None
I am aiming to modify an attribute of A within the function body of one of its attributes. I hope I have made the question clear. Any help would be appreciated!
Thank you!
OOP is about encapsulation. An instance b of B should not be allowed to modifiy a parameter of an instance of a of A unless: 1. a is an attribute of b or 2. a is a parameter of a method of b. Since b is a parameter of a, it would be a really bad design to have a a parameter of b. Hence you have to pass a as a parameter.
Here's a working code that respects encapsulation:
class A(object):
def __init__(self, b, c):
self.attribute_b = b
self.attribute_c = c
class B():
def foo(self, a):
a.attribute_c = None
return "result"
beta = B()
charlie = "C"
alpha = A(beta, charlie)
print(alpha.attribute_c) # prints C
alpha.attribute_b.foo(alpha)
print(alpha.attribute_c) # prints None
But this is really poor design. Because one day you'll see this:
alpha1.attribute_b.foo(alpha2)
And you have no way to prevent this. Here's a better code:
class A(object):
def __init__(self, b, c):
self.attribute_b = b
self.attribute_c = c
def foo(self):
self.attribute_b.foo(self)
class B():
def foo(self, a):
a.attribute_c = None
return "result"
beta = B()
charlie = "C"
alpha = A(beta, charlie)
print(alpha.attribute_c) # prints C
alpha.foo()
print(alpha.attribute_c) # prints None
Remark: The State pattern uses a similar design. The Context has a State parameter. The handle method of the State takes a reference on the Context as parameter to be able to change the current state by calling context.set_state(NextState()).
I know this is a noob question but I am learning OOPs and can't able to figure the outputs got
This is the code I found and may i know how this runs?
class InstanceCounter(object):
count = 0
def __init__(self, val):
self.val = val
InstanceCounter.count += 1
def set_val(self, newval):
self.val = newval
def get_val(self):
print(self.val)
def get_count(self):
print(InstanceCounter.count)
a = InstanceCounter(5)
b = InstanceCounter(10)
c = InstanceCounter(15)
for obj in (a, b, c):
print("value of obj: %s" % obj.get_val())
print("Count : %s" % obj.get_count())
You have a class called InstanceCounter which inherits from object. The inherince from object can be removed if you use Python3. This class has an attribute count and value and some methods (functions - for example set_val).
Now you create three objects of your class and set the value of value to 5, 10 and 15 by passing these values into the constructor. You also increase the static attribute (see here) count by one with each constructor call. A static attribute is used with the notation Class.Attribute.
In the last step you loop over a list of your three objects ((a, b, c)) and store each of this object in the object obj, so obj will represent a then b and then c. So you can call the methods of this object, because your object obj has the type InstanceCounter and so obj contain the same methods and attributes.
By the way I have reworked your code so make it more understandable and use Python3 syntax.
class InstanceCounter:
count = 0
def __init__(self, val):
self.val = val
InstanceCounter.count += 1
def set_val(self, newval):
self.val = newval
def get_val(self):
return self.val
def get_count(self):
return InstanceCounter.count
a = InstanceCounter(5)
print("Count : {}".format(a.get_count()))
b = InstanceCounter(10)
print("Count : {}".format(b.get_count()))
c = InstanceCounter(15)
print("Count : {}".format(c.get_count()))
for obj in (a, b, c):
print("value of obj: {}".format(obj.get_val()))
print("Count : {}".format(obj.get_count()))
This result in the following output:
Count : 1
Count : 2
Count : 3
value of obj: 5
Count : 3
value of obj: 10
Count : 3
value of obj: 15
Count : 3
For a better understanding of static attributes:
So if you have three objects with type InstanceCounter you have three different attributes with name val because each object with type InstanceCounter contains one attribute val - an instance attribute and one identical attribute with name count - a class attribute.
count is a class attribute for the class InstanceCounter. This
attribute has the same value for all objects with type
InstanceCounter. Used with Classname.Attributename - for example InstanceCounter.count.
val is a instance attribute because each instance of a class InstanceCounter has his own value. Used with Instancename.Attributename - for example a.val.
See here for more information.
I'm currently trying to build a simple animation for a queuing model and I want to set the coords of any graphical object in dependence of its predecessor object. To do so, I call a method of the object (o1), which I want to animate. This method creates an object (o2) of another class, which represents the image. While creating o2, I want to pass an attribute of o1. This looks, for instance, like this:
class Queue(salabim.Queue):
def setup(self, predecessor):
self.predecessor = predecessor
def animate(self, graphic):
self.graphic = graphic
buffer_preprocessing = Queue(
name = 'buffer_preprocessing',
predecessor = source)
if env.animation is True:
buffer_preprocessing.animate(graphic = Symbol_Queue(
width = 80,
height = ref_height,
slots = 5,
x = predecessor.graphic.x + predecessor.graphic.width + distance,
y = y0,
fillcolor = 'white'))
When compiling the program, I receive an error "[pylint] Undefined variable 'predecessor' [undefined-variable]".
Can somebody tell me, which keyword I need to use to refer to the attributes of the outside object "buffer_preprocessing"?
Thanks in advance :-)
Edit: It is possible to simplify my problem to the following code:
class OuterClass():
def __init__(self, A):
self.A = A
def do_stuff(self, stuff):
self.stuff = stuff
class InnerClass():
def __init_(self, B):
self.B = B
outerclass = OuterClass(A=1)
outerclass.do_stuff(stuff = InnerClass(B = 1 + A))
# Error: Undefined variable 'A'
# How can I refer to the calling object 'outerclass' without giving the explicit name?
I am guessing both the Queue and the Symbol_Queue since neither the name nor the predecessor parameters are part of python's queue.Queue.
If this is so, I believe the change needs to be implemented inside the code of the Queue class... maybe something along the lines:
First, expose the predecessor inside the Queue
class Queue(...):
def __init__(self, name, predecessor, ...):
...
# expose the predecessor
self.predecessor = predecessor
or alternatively, if you need to do some processing/checking you can expose a property
class Queue(...):
def __init__(self, name, predecessor, ...):
...
# expose the predecessor
self._predecessor = predecessor
#property
def predecessor(self):
# .. some checks or processing
return self._predecessor
Second, your code above will now become something like:
buffer_preprocessing = Queue(
name = 'buffer_preprocessing',
predecessor = source)
if env.animation is True:
buffer_preprocessing.animate(graphic = Symbol_Queue(
width = 80,
height = ref_height,
slots = 5,
x = buffer_preprocessing.predecessor.graphic.x + buffer_preprocessing.predecessor.graphic.width + distance,
y = y0,
fillcolor = 'white'))
There probably might be better ways to pass this by changing a little the implementation of the .animate, but it's hard to say without looking at the implementation of the Queue and Symbol_Queue classes.
EDIT 1: Using the simpler abstraction added to the question
I believe the key here would be to include some kind of logic inside the OuterClass.do_stuff, since in there you can access the things within self. Of course, it depends how much you can "hardcode" into this function on the OuterClass.
Here is a suggestion (I define the Inner first for better readability):
class InnerClass():
def __init_(self, B):
self.B = B
class OuterClass():
def __init__(self, A):
self.A = A
def do_stuff(self, stuff_to_create_inner):
new_inner = InnerClass(B = 1 + self.A, **stuff_to_create_inner)
# You can use "**" (dict unpacking), or pass them "by hand"
# ...
self.stuff = stuff
outerclass = OuterClass(A=1)
outerclass.do_stuff() # in your example you may want to pass the width, height, ...
Finally, should you need to use/keep track of that inner object you created (I'm guessing you don't since you simply create on inside the method call), you could always have OuterClass.do_stuff return the created object.
Thanks for the simplification. Now it’s much clearer. In that case, you can simply pass the class as well as the argument to do_stuff rather than creating an object when calling the do_stuff function. For example,
class OuterClass():
def __init__(self, A):
self.A = A
def do_stuff(self, my_class, other_input):
self.obj = my_class(other_input+self.A)
class InnerClass():
def __init_(self, B):
self.B = B
outerclass = OuterClass(A=1)
outerclass.do_stuff(my_class = InnerClass, other_input=1)
Why when I create a class with a list, the list and its contents become global
class A:
my_list = []
string = ""
def add(self, data):
self.string += "a"
self.my_list.append(data)
def print_list(self):
print(self.string)
print(self.my_list)
a = A()
b = A()
a.add("test")
a.print_list()
b.print_list()
Both a and b will print the list that was created by a.add
# results of a.print_list
xa
['test']
# results of b.print_list
x
['test']
So my question is, is this normal for python3, or a bug.
Doesnt seem right to me that only the list is modified globally.
This is the explaining:
Objects have individuality, and multiple names (in multiple scopes) can be bound to the same object. This is known as aliasing in other languages. This is usually not appreciated on a first glance at Python, and can be safely ignored when dealing with immutable basic types (numbers, strings, tuples). However, aliasing has a possibly surprising effect on the semantics of Python code involving mutable objects such as lists, dictionaries, and most other types. This is usually used to the benefit of the program, since aliases behave like pointers in some respects. For example, passing an object is cheap since only a pointer is passed by the implementation; and if a function modifies an object passed as an argument, the caller will see the change — this eliminates the need for two different argument passing mechanisms as in Pascal.
From oficial Python 3 docs
And this is the solution:
(...) use an instance variable instead (...)
Like this:
class Dog:
def __init__(self, name):
self.name = name
self.tricks = [] # creates a new empty list for each dog
def add_trick(self, trick):
self.tricks.append(trick)
Result of above code:
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks ['roll over']
>>> e.tricks ['play dead']
In your example, you should move your my_list = [] declaration to the init function...
class A:
string = ""
def __init__(self):
self.my_list = []
def add(self, data):
self.string += "a"
self.my_list.append(data)
def print_list(self):
print(self.string)
print(self.my_list)
a = A()
b = A()
a.add("test")
a.print_list()
b.print_list()
Hope this help.
Regards
Strings are immutable so
self.string += "a"
creates a new object and binds it to self.string
This is clearly mutating the list in place
self.my_list.append(data)
Perhaps more interesting is that
self.my_list += [data]
also mutates the list
The general rule is that __iadd__ does behave differently for mutable vs immutable objects