Pass arbitrary number of variables through multiple functions/classes/methods - python

I have a class with methods that looks something like this
class A(object):
def __init__(self, strat):
self.strat_cls = strat
self._genInstances()
def _genInstances(self):
self.strat = self.strat_cls(self.x, self.y)
and the strat_cls:
class strat1(Strat):
def __init__(self, x=4):
self.x = x
def calculate_something(self, event):
if x > 2:
print("hello")
I initialize everything by:
example = A(strat1)
When initializing I need to be able to pass an arbitrary number of arguments to the calculate_something method in the strat1 class like this:
example = A(strat1, x=3)
or
example = A(strat1, x=3, y=5)
where y will then be used further down in the calculate_something method.
How do I do that? I need to be able to pass both "new variables" and overriding the x variable. I've tried several times using *args and **kwargs, but I end up with errors.

Here is your code with comments. The main point is you have to save the arguments in A and pass them to strat when you're initializing it.
class A(object):
def __init__(self, strat, **strat_kwargs):
self.strat_cls = strat
# save kwargs to pass to strat
self.strat_kwargs = strat_kwargs
self._genInstances()
def _genInstances(self):
# init strat with kwargs
self.strat = self.strat_cls(**self.strat_kwargs)
class strat1(Strat):
def __init__(self, x=4, y=None):
# save x and y
self.x = x
self.y = y
def calculate_something(self, event):
# use self.x here
if self.x > 2:
print("hello")

Related

Python: Using property get/set to run on sub-class function

I have a setup that looks something like this simplified setup:
class WorkerBee():
def __init__(self):
self.x = 1
self.old_x = None
def update_x(self, val):
self.update_old_x()
self.x = val
def _update_old_x(self):
self.old_x = self.x
class MainClass():
def __init__(self):
self.bee = WorkerBee()
def updated_WorkerBee(self):
print('yay, it was updated')
I understand the use of #property to do a get - set setup for an attribute. But in this case, I'm trying to figure out how I can directly call the WorkerBee methods (there are more than 1 in my case....) that would also trigger MainClass.updated_WorkerBee()
In:
main = MainClass()
main.bee.update_x(2)
Out:
yay, it was updated
Any help is appreciated!
You could add a reference to the main object to the bee, like a parent:
class WorkerBee:
def __init__(self, main):
self.main = main
self.x = 1
(...)
and then use it in your update methods within WorkerBee, to update main too:
def update_x(self, val):
self.update_old_x()
self.x = val
self.main.updated_WorkerBee()
To do that, pass the main to the bee when you create it:
class MainClass:
def __init__(self):
self.bee = WorkerBee(self)

Cannot mutate default parameter list of derived class

The is a minimized script I have:
import random
def genvalue():
return random.randint(1, 100)
class A(object):
def __init__(self, x = genvalue()):
self.x = x
class B(A):
def __init__(self):
super(B, self).__init__()
t1 = A(10)
t2 = B()
t3 = B()
print t1.x
print t2.x
print t3.x
The expected result I wanted is t1.x having the value 10, and the other two having random values, but instead both t2 and t3 have the same values, it is like the genfunc is only called once. I would like to have it called each time when an instance is initiated. Is it possible to do it without messing with the function signatures?
Default arguments are evaluated at callable creation time.
Currently, genvalue is called exactly once in your program, at the time the method __init__ is being being built in order to bind the default value of x to the method.
Demo:
import random
def genvalue():
print('genvalue called')
return random.randint(1, 100)
class A(object):
def __init__(self, x=genvalue()):
self.x = x
print('creating some instances...')
A()
A()
A()
print(A.__init__.__defaults__)
Output:
genvalue called
creating some instances...
(32,)
Use
class A(object):
def __init__(self, x=None):
self.x = x if x is not None else genvalue()
genfunc is only called once - when the class description is read for the first time. The parameter is evaluated there - it's not evaluated each time the class is created.
Instead set the default value to None, and if a value isn't given, generated it in your __init__ method instead.
class A(object):
def __init__(self, x=None):
if x is None:
x = genvalue()
self.x = x

Python method using class variables, right approach

I have a question about python using OOP.
If I have two classes, and a method which takes variables from those classes, I pass the classes as parameters of the method as shown below. I am sure that this is not the right approach, and this is why I would like to know an alternative and more efficient way to do it. Specifically:
class Player(object):
x_player = 5
y_player = 5
class Food(object):
x_food = 10
y_food = 10
def method(Player, Food):
if Player.x_player > Food.x_food:
print('Food behind)
if Player.x_player < Food.x_food:
print('Food in front')
Is this correct? If I use the method def __init(self)__ then I cannot pass those variables in the function.
Thank you
If I use the method def init(self) then I cannot pass those variables in the function.
This understanding is wrong, as you can add parameters to __init__.
How about this? Or you still insist to use class method? If you choose class method, your solution already ok, just call with method(Player, Food) or even you did not need the parameters added in the function.
class Player(object):
def __init__(self, x, y):
self.x_player = x
self.y_player = y
class Food(object):
def __init__(self, x, y):
self.x_food = x
self.y_food = y
def method(player, food):
if player.x_player > food.x_food:
print('Food behind')
if player.x_player < food.x_food:
print('Food in front')
method(Player(5, 5), Food(10, 10))
if those are class variables, you can just refer to those variables as classname.var_name:
class A:
a = 10
if __name__ == '__main__':
print(A.a)
if the values are defined by instance, then you need to instantiate the class variables and then you can perform comparison on that
class A:
def __init__(self, a):
self.a = a
if __name__ == '__main__':
x = A(5)
y = A(10)
print(x.a > y.a)
>> False
Also this is python and in python you don't specify the data types of function arguments so you can send any object and be carefree of which class' instance it is. You code should handle the exceptions if a wrong class' object is sent.
class A:
def __init__(self, a):
self.a = a
class B:
def __init__(self, a):
self.a = a
def fun(obj):
print(obj.a)
if __name__ == '__main__':
x = A(5)
y = B(10)
fun(x)
fun(y)
>> 5
>> 10
class A:
def __init__(self, a):
self.a = a
class B:
def __init__(self, a):
self.a = a
def fun(obj):
if not isinstance(obj, B):
print(obj.a)
if __name__ == '__main__':
x = A(5)
y = B(10)
fun(x)
fun(y)
>> 5

python; how to pass one argument through multiple methods in a class

I am learning about class structure in python. Would like to know if it's possible to pass one argument through more than one method.
class Example(object):
def __init__(self, x):
self.x = x
def square(self):
return self.x**2
def cube(self):
return self.x**3
def squarethencube(y):
sq = Example.square(y)
cu = Example.cube(sq)
return cu
two = Example(2)
print(two.squarethencube())
Error is on line 10; AttributeError: 'int' object has no attribute 'x'
The goal is to use the 'squarethencube' method to pass '2' to square(), which is 4. Then pass '4' to cube(). The desired output is '64'. Obviously, you can write a function to do the math in a very simple way; the question here is how to use multiple methods.
I understand the error in that .x is getting assigned as an attribute onto the output of cube(sq). I was getting the same error, but on line 7, before I changed the argument to y (from self.x).
I've found some similar answers here but I need a simpler explanation.
Currently, square and cube are methods bound to the class; however, you are accessing them in squarethencube by class name, but they are methods, and thus rely on a reference to the class from an instance. Therefore, you can either create two new instances of the class or use classmethod:
Option1:
class Example(object):
def __init__(self, x):
self.x = x
def square(self):
return self.x**2
def cube(self):
return self.x**3
def squarethencube(self, y):
sq = Example(y).square()
cu = Example(y).cube()
return cu
Option 2: use a classmethod:
class Example(object):
def __init__(self, x):
self.x = x
#classmethod
def square(cls, x):
return x**2
#classmethod
def cube(cls, x):
return x**3
def squarethencube(self, y):
sq = Example.square(y)
cu = Example.cube(sq)
return cu
class Example:
def __init__(self, x):
self.x = x
def square(self):
return self.x**2
def cube(self):
return self.x**3
def squarethencube(self):
return (self.x**2)**3
two = Example(2)
print(two.squarethencube())

How to Nested Classes in Python when trying to write a __call__ overwrite

So hopefully below illustrates my point. I want to set the translate attributes once and then be able to pass any mods (like translate) into the modLevels function. The only way I know how to do this is through nested classes, but I can't figure out how to get access to the outer class points. Any ideas or maybe even let me know if I'm going about this all wrong. THANKS!
class PointSet:
def __init__(self, points):
self.points = points
class translate:
def __init__(self, xmove=0, ymove=0):
self.xmove = xmove
self.ymove = ymove
def __call__(self):
for p in Outer.points: # <-- this part isnt working
p.x += self.xmove; p.y += self.ymove
def modLevels(levels, *mods):
for lev in range(levels):
for mod in mods:
mod
set1 = PointSet(...list of point objects here...)
coolMod = translate(xmove=5)
change(5, coolMod)
Pass it as a parameter.
class PointSet:
def __init__(self, points):
self.points = points
class translate:
def __init__(self, xmove=0, ymove=0, parent):
self.parent = parent
self.xmove = xmove
self.ymove = ymove
def __call__(self):
for p in self.parent.points:
p.x += self.xmove; p.y += self.ymove
Self-contained example:
class A:
def __init__(self):
self.data = [1,2,3]
class B:
def __init__(self, parent):
self.data = [4,5,6]
self.parent = parent
def access(self):
print(self.parent.data)
a = A()
b = a.B(a)
b.access()
However, as explained in comments, you don't need a nested class at all.
class PointSet:
def __init__(self, points):
self.points = points
def translate(self, x, y):
for p in self.points:
p.x += x
p.y += y
Thank you all for your help. I found a way to access the outer class on ubuntu forums. Solved referencing outer class from an inner class.
I needed to do this to pass a few parameters to the translation constructor and then overwrite the call function to use those parameters. This is a similar concept to a C++ function object like what you would pass to an STL algorithm: more on function objects.

Categories