Add non-lamda function to self of Python class - python

Adding lambda expression to self of a Python class is easy:
class Foo(object):
def __init__(self, x):
if x > 0:
self.eval = lambda x: x
else:
self.eval = lambda x: x**2
return
def compute(self, y):
return self.eval(y)
In my case, self.eval is somewhat more complex such that it doesn't fit into a one-line lambda. I need def. How can I assign self.eval with a defined function though?
For performance reasons, I would like to not store self.x = x and not move the if into compute.

You can define a function anywhere:
class Foo(object):
def __init__(self, x):
if x > 0:
def eval(y):
return y
else:
def eval(y):
return y**2
self.eval = eval
def compute(self, y):
return self.eval(y)

Python functions are first class objects. You can assign any function to a variable:
class Foo(object):
def __init__(self, x):
if x > 0:
self.eval = self.method1
else:
self.eval = self.method2
def method1(self, x):
return x
def method2(self, x):
return x * x
def compute(self, y):
return self.eval(y)
f1 = Foo(1)
print(f1.compute(10)) # 10 (method1)
f2 = Foo(-1)
print(f2.compute(10)) # 100 (method2)

At least in Python 3 it is trivial to add a method to an existing class. Just look at the following code:
>>> class A:
val = 2 # declare a class variable (will be the default value
>>> def func(self, x): # declare a function that will be added as a method
return self.val * x
>>> A.compute = func # add the compute method to class A
>>> a = A() # create an instance
>>> a.val # control the value of the member
2
>>> a.compute(3) # use the added method
6
>>> a.val=3 # change the value of the variable for the specific instance
>>> a.compute(4) # control that the new variable value is used
12

Related

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

Is it possible to create a method by an argument

Say I have two functions
def do1(x, y):
return x + y
def do2(x, y):
return x - y
I can create a class like this
class foo(object):
def __init__(self, func):
self.func = func
abc = foo(func=do1)
abc.func(1, 1) # return 2
abc = foo(func=do2)
abc.func(1, 1) # return 0
Is it possible for me make abc.func to be a method rather than an attribute?
Thanks.
You can add a method to a class like so:
def do(self, x, y):
return x+y
class Foo(object0:
def __init(self):
pass
Foo.bar = do
a = Foo()
a.bar(1,2)
out> 3
Or to an instance:
def do2(x,y):
return x + y
a = Foo()
a.bar2 = do2
a.bar2(3,4)
out> 7

In the main function, how to print the value (x,y) from the def __str__?

for example
def __str__ (self):
return (x,y)
def main():
how do u print the value of x and y from the def str(self): function
Would really appreciate it thanks!!!
That code doesn't make sense, so I'm extrapolating.
I'm assuming you have some class like so:
class Foobar(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return str((x,y))
def main():
foobar = Foobar(1,2)
main()
In this case, you COULD use string manipulation to handle it.
x_value, y_value = map(str.strip("()"), str(foobar).split(','))
But that's uglier than sin. Why not just reference the values directly?
x_value, y_value = foobar.x, foobar.y
Using the example in Adam's answer:
class Foobar(object):
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return '({foo.x}, {foo.y})'.format(foo=self)
Would result in:
foo = Foobar(2, 3)
print(foo)
'(2, 3)'

Python: avoid defining both a classmethod and an instancemethod

NOTE on the question below. I think the 'proper' pythonic idiom is to a) create module functions, such as foo_math below, and then call their specific action against an instance within the class itself. The bottom piece of code reflects that approach.
I want to define a classmethod which takes two arguments and returns a value. I want the same method to be able to be called on a class instance with the instance value pass as one of the arguments. Can I do this without defining two distinct methods as I have done here?
class Foo(object):
__init__(x):
self.x = x
#classmethod
def foo_math(cls, x, y):
return x + y
def math(self, y):
return Foo.foo_math(self.x, y)
What I would like is:
>>> Foo.math(3, 4)
7
>>> f = Foo()
>>> f.x = 3
>>> f.math(4)
7
Short of subtyping int, here is my conclusion to this question:
def foo_math(cls, x, y):
return x + y
class Foo(object):
__init__(x):
self.x = x
def foo_math(self, y):
return foo_math(self, y)
i don't recommend doing this, but if you really want, it's this (thank you other guy on stackoverflow for first part):
class staticorinstancemethod(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return functools.partial(self.func, instance)
then, do something like
class F(object):
#staticorinstancemethod
def math(instOrNone, v1, v2=None):
return instOrNone.x + v1 if instOrNone else v1 + v2
but maybe you just want to define the __add__ and __radd__ methods...
I don't think that you can call a method from a class without defining an object of that class (class methods don't belong inside the methods of any one class), so things like Foo.math(3, 4) will return a NameError as Foo has not been defined.
With this in mind, you should modify your code to be like this (even though with the problem solved there are still some issues with the code):
# A class method would probably go here somewhere.
class Foo(object):
def __init__(self, x):
self.x = x
def foo_math(self, x, y):
return x + y
def math(self, y):
return self.foo_math(self.x, y)
Then you can do:
>>> f = Foo(3)
>>> f.math(4)
7

Categories