How to refer to an attribute of a first object, which creates with a method a second object? - python-3.x

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)

Related

What is the purpose of constructor in Python?

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

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

OOP - Call function containing instance of class within the same class

I am new to programming and have done some research on instance, class, and static variables. Lately, I have tried to simplify my code on my projects to help me learn more in Python. In this particular instance, no pun intended, I'd like to be able to call the somefoo() function that will assign arguments to the init instance variables one and two, depending on conditions. From my understanding, in order to call the somefoo() function, the Foo() class must be instantiated; however, the parameters the class requires are within the somefoo() function within that class. Thank you in advance!
import random
class Foo():
def __init__(self, one, two):
self.foobar = random.random()
self.one = one
self.two = two
def somefoo(self):
if self.foobar > 0.5:
one = ':)'
two = 1
Foo(one, two)
if self.foobar < 0.5:
one = ':('
two = 0
Foo(one, two)
somefoo()
To begin with, I don't even know if you have checked your code before posting it here for help because there is something really wrong with it. There are lot of syntax mistakes. This is how it's supposed to be...
import random
class Foo:
def __init__(self, one, two):
self.foobar = random.random()
self.one = one
self.two = two
def somefoo(self):
if self.foobar > 0.5:
one = ':)'
two = 1
Foo(one, two)
if self.foobar < 0.5:
one = ':('
two = 0
Foo(one, two)
somefoo()
There were parenthesis before the class name which were not required in python along with useless indents. Python is sensitive when it comes to indents so make sure your indents are meaningful, and use them logically. Now coming to your question; here is how it can be done:
import random
class Foo:
def __init__(self, one, two):
self.foobar = random.random()
self.one = one
self.two = two
self.somefoo()
def somefoo(self):
if self.foobar > 0.5:
self.one = ':)'
self.two = 1
if self.foobar < 0.5:
self.one = ':('
self.two = 0
def __str__(self):
return str(self.one)+" "+str(self.two)
print(Foo(10,20))
Basically the part where you are trying to call somefoo is not wrong and yes python does execute the class down to the bottom when it makes a object of it in memory, but in your code the method is of bound type (i.e. it needs and object for execution). So what you can do is use some sort of object factory pattern, or go with the one I have pasted above, in which as soon as object is generated, it calls the bound method which swipes the data of instance in question and displays the output. In python3 unbound methods are introduced which can be used without the self object reference. Make sure you look into them too and how they work, as they may help you to come with more flexible solution to your problems.

How to get a list of areas out of a class bassed system

So I am in an intro to python class and we are just getting into class basses coding in python. I am looking to get a list of areas out of the plants in my list so that I can then take those areas, get a sum, and then subtract them from the area in the bed. I am having the trouble figuring out how to make a list of the area of the plants in my bed, which is only blueberries for now. Any ideas are greatly appreciated.
class crop:
name = "Crop"
sizeW = 0
sizeL = 0
areaOfCrop=sizeL * sizeW
def print(self):
print("This is a ",self.name," and is ",self.sizeW,"X",self.sizeL, "and has an area of ",self.areaOfCrop)
def willItFit(self, W, L):
return self.sizeW <= W and self.sizeL <= L
def sameAs(self, crop):
return self.name == crop.name
class plant(crop):
name = "Plant"
sizeW = 1
sizeL = 1
areaOfCrop = sizeL * sizeW
class parsley(plant):
name = "Parsley"
class shrub(crop):
name = "Shrub"
sizeW = 2
sizeL = 2
areaOfCrop = sizeL * sizeW
class blueberries(shrub):
name = "Blueberries"
class tree(crop):
name = "tree"
sizeW = 3
sizeL = 3
areaOfCrop = sizeL * sizeW
class dwarfPeach(tree):
name = "Dwarf Peach"
class bed:
sizeL = int(input("What is the length? "))
sizeW = int(input("What is the width? "))
crops = [blueberries()] # The list of crops in this bed
areaOfAllCrops = [crops[areaOfCrop()]] #this is where my problem is
def print(self):
print("The bed is ", self.sizeL," x ", self.sizeW)
for c in self.crops:
c.print()
def maxSizeAvailable(self):
''' area of bed-total area of all crops in be '''
return (self.sizeW, self.sizeL)
def add(self, newCrop):
dimension = self.maxSizeAvailable()
if newCrop.willItFit(dimension[0], dimension[1]):
self.crops.append(newCrop)
def remove(self, existingCrop):
for c in self.crops:
if c.sameAs(existingCrop):
self.crops.remove(c)
def checkFit(self, crop):
dimension = self.maxSizeAvailable()
return crop.willItFit(dimension[0], dimension[1])
b = bed()
b.print()
You can add up the areas of the crop instances in the crops list with sum(x.areaOfCrop for x in crops). This is a generator expression that gets passed to the builtin function sum.
But I think you have a larger conceptual issue that will cause you problems later on even you get your immediate issue squared away. The issue is that you're exclusively using class attributes in your code, rather than instance attributes. While there are some situations where class attributes are useful, the overwhelming majority of the time you want to be dealing with instance attributes instead.
To create instance attributes, you need to make the assignments in a method, and assign to self.attr instead of just attr. Usually the place to initialize your instance attributes is the __init__ method, which Python will call for you after it creates the new instance.
To give an example, your crop class should probably start with:
class crop:
def __init__(self):
self.name = "Crop"
self.sizeW = 0
self.sizeL = 0
self.areaOfCrop = sizeL * size
# ...
Some of those values could be passed as arguments, rather than always getting set to the same constant. That leads me to a design question: Do you need all of your different plants to be instances of separate classes, or could they all be different instances of one class, with different data in their instance attributes attributes? (Don't be too concerned if you don't know the answer yet. It takes some experience with OOP to get good at designing classes.)

Resources