What is the purpose of constructor in Python? - python-3.x

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

Related

Variable declaration as a member of a function?

What type of declaration is the one indicated in this code
def call_counter(func):
def helper(x):
helper.calls1 += 1 # <== This
return func(x)
helper.calls1 = 0
return helper
#call_counter
def succ(x):
return x + 1
print(succ.calls1)
for i in range(10):
print(succ(i))
print(succ.calls1())
What's the name of this is the first time i see something like this
Functions are just objects in Python, so the same way you can add new attributes to instances of your own classes (and to the classes themselves) you can add them to your functions:
def foo():
pass
class Bar:
pass
bar = Bar()
foo.spam = 1
bar.spam = 2
print(foo.spam) # 1
print(bar.spam) # 2
Generally one wouldn't add new attributes to a function object though, since it can quickly get messy and hard to keep track of.

Is there a way to pass all variable to a function in python

I have part of a function I would like to turn into another function. I want this new function to be able to edit the variables in in the parent function. Is this possible in python.
I know in other languages that a class can inherent their parents variables and function. I am wondering if there is something similar to this in python?
check here for scoping then here and here for closures. You are ideally looking for enclosing functions. The variables defined within the enclosing functions are available to the sub-functions as though they were globally defined. Most of these are widely dealt with in other languages.
def m(x,y):
z = 2
j = 4
def n():
return x+y+z+j
return n()
m(3,1)
10
is that what you are looking for !
class Parent:
# two class variables x,y
x = 100
y = 100
def __init__(self):
pass
def sum_from_parent(self):
return self.x+self.y
class Child(Parent):
def __init__(self):
super().__init__() # init super class to create x,y variables
def sum_child(self):
# edit base class variables
x_in_child = Parent.x+20
y_in_child = Parent.y+20
return(x_in_child+y_in_child)
c = Child()
print("sum in parent = ", c.sum_from_parent())
print("sum in child = ", c.sum_child())
answer will be
sum in parent = 200
sum in child = 240

Creating new object keeps data even with default value

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)

How to access attribute from within a separate attributes method body?

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

How to refer to an attribute of a first object, which creates with a method a second object?

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)

Resources