Python: Passing an instance to a nested function - python

class A:
def __init__(self, x, y):
self.base = x
self.core = y
def addBaseCore(self, initial):
def addBase(z): # vs. def addBase(self, z)
return z + self.base
initial += self.core
# vs. Do we pass self to the nested function? e.g. addBase(self, z)
return addBase(initial)
I am new to Python and I am curious how/why is it possible to access the attributes of an instance within a nested function without explicitly passing the instance to the nested function (as shown above)?
The inner method is not exactly an instance method neither does it receive the instance as an argument. How is the inner method still able to access the attributes of the instance?
Thank you for all the help.

There's no need to pass self into the nested function that's defined inside your member function.
Here's an example using your code.
a = A(10, 20)
print(a.addBaseCore(30))
Output
60

Related

Calling class function saved as attribute

I have two classes and a "use" class function that performs multiple actions using the various attributes as the inputs so that I can just call the one function and get different results based on which class object is referenced. Where I am getting stuck is that I want to have part of the use function check the 'effect' attribute and call the function found there. Currently, the function named in effect is called when the object c is defined, and everything I have tried within the use function has no effect or returns 'none' since I don't have a return statement in the add and sub functions.
I've provided a simplified example code below. C has 9 attributes and 10 different class functions that I would want to use in the effect spot. I plan on having 50+ different C objects, so not having to write out specific functions for each one would be spectacular.
In this example, the print(p.h) at the end returns 101, showing that designing the C object calls the add function I put in the attribute:
M= []
class P:
def __init__(p, h, s):
p.h= h
p.s=s
class C:
def __init__(y, name, d, f effect,):
y.name= name
y.effect= effect
y.d= d
y.f= f
def use(c):
M.append(c)
p.h -= p. y.d
p.s += y.f
effect
def add(c, x):
p.h += x
def sub(c, x):
p.h -=x
p= P(100)
c= C('test1', add(1), 1)
print(p.h)
I have tried the add and sub functions as both class and standalone, which didn't seem to make a difference, calling y.effect as though it were a function which just returns 'none' as mentioned, and adding the property decorator, which threw an error, probably because I don't quite understand what that is supposed to do yet.
When accessing methods of classes C and P, you will only be able to access them from the class namespace. C.add will work, but add will not.
Furthermore if you call c.add(4) it will be the same thing as calling C.add(c, 4) because it will implicitly pass the instance c into the class (C) method C.add. You cannot call add(1) or c.add(1) before your instance c is initialized by the __init__ method.
Typically when writing python, it is most clear to always name the first argument to your class method self to make it clear that self refers to the instance and that it will automatically get passed into the function.
Furthermore, because you do not instantiate p until after you define your class C, you won't be able to access p from inside your C class unless you pass p into the function or save it as an attribute of c.
Not totally sure what you are going for here but I made some modifications which might help.
#!/usr/bin/env python
M = []
class P:
def __init__(self, h, s):
# self refers to your instance of p
self.h = h
self.s = s
class C:
def __init__(self, name, p, d, f, effect):
# self refers to your instance of c
self.p = p # save an instance of p as an attribute of your instance of c
self.name = name
self.effect = effect
self.d = d
self.f = f
def use(self):
M.append(self)
self.p.h -= self.d
self.p.s += self.f
return self.effect
def add(self, x):
# self refers to your instance of c and gets implicitly passed in as the first argument
# when c.add(2) is called
self.p.h += x
def sub(self, x):
self.p.h -= x
p = P(100, 50)
c = C('test1', p, d=2, f=1, effect="a")
c.add(1)
print(p.h)
<script src="https://modularizer.github.io/pyprez/pyprez.min.js"></script>
This code isn't runnable as-is, so there may be other problems with your real code that aren't possible to discern from this example, but when you say:
function named in effect is called when the object c is defined
that's happening not because of what's inside your C class, but the line where you construct your C:
c= C('test1', add(1), 1)
The expression add(1) isn't passing the add function, it's calling the add function and passing its result. To pass a function as an argument, just pass the function itself without the ():
c = C('test1', add, 1)
Note that in the code you provided there is no function called add in the current scope, and your C.use does not call effect, which is a different problem.

Is there a way to use staticmethod in a class attribute in python? [duplicate]

This question already has answers here:
referencing class methods in class lists in Python
(7 answers)
Calling class staticmethod within the class body?
(6 answers)
Closed last year.
I would like to define a class such as the following FunctionCatalogue class. In this class, there is a catalogue of staticmethod. These methods can thus be used without instantiating the class. The functions are labeled from tuple of integers. I defined the __call__ special method to be able to compute the relevant function values when the class is instantiated.
In order to do the same but without instantiating the class, I would had like to define the dictionary functions as a class attribute that provides the link between the tuple of integers and the give functions. But, as expected, the this_class is not defined neither FunctionCatalogue or obviously self as the class was not yet instantiated.
I wonder if there is a way to implement this or maybe a better approach to do the same ?
class FunctionCatalogue:
functions = {
(0, 0): this_class.func1,
(0, 1): this_class.func2,
}
def __init__(self, i, j):
self.i = i # with tests on i values
self.j = j # with tests on j values
#staticmethod
def func1(x):
return x + 1
#staticmethod
def func2(x):
return 2 * x + 2
def __call__(self, x):
return self.functions[(self.i, self.j)](x)
To be more clear, the idea is to be able to do
>>> my_f = FunctionCatalogue(0, 0)
>>> my_f(2)
or something like
>>> FunctionCatalogue.func1(2)
or
>>> FunctionCatalogue.functions[(0, 0)](2)

Is self variable computed multiple times if functions are called more than once in Python?

I have a class where the shared variable self.a is obtained after a very heavy computation which requires a lot of time:
class MyClass(object):
def __init__(self):
# ----------------------------------
# function computationally demanding
out = demanding_function() # In this example, the output is a list of characters ['A','X','R','N','L']
# ----------------------------------
self.a = out
def fun1(self, string):
out = []
for letter in self.a:
out.append(string+letter)
return out
def fun2(self, number):
out = []
for letter in self.a:
out.append(str(number)+letter)
return out
o = MyClass()
x = o.fun1('Hello ')
y = o.fun2(2)
As you can see, self.a is used by the functions fun1 and fun2.
Here is my question is the following: if I call those 2 functions, is the demanding_function() executed multiple times or just once?
Note: this is a generic example and the variables don't have any specific meaning
The function is called just once, when the class instance is initialised i.e. when the __init__ of the class is called. Every other time you access self.a, the already assigned value is used; so no worries.
__init__ is only called once, when you instantiate the object. Any subsequent method calls using that instantiated object will use the already-computed values of instance varaibles

How can I make a class method return a new instance of itself?

I have a python class which has a few lists and variables(initialized in __init__).
I want to have a method which operates upon this particular instances data and returns a new instance(new data). In the end, this method should return a new instance with modified data while leaving the original instance's data intact.
What is a pythonic way to do this?
EDIT:
I have a method in the class called complement() which modifies the data in a particular way. I would like to add a __invert__() method which returns an instance of the class with complement()ed data.
Example: Suppose I have a class A.
a=A()
a.complement() would modify the data in instance a.
b = ~a would leave the data in instance a unchanged but b will contain complement()ed data.
I like to implement a copy method that creates an identical instance of the object. Then I can modify the values of that new instance as I please.
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def copy(self):
"""
create a new instance of Vector,
with the same data as this instance.
"""
return Vector(self.x, self.y)
def normalized(self):
"""
return a new instance of Vector,
with the same angle as this instance,
but with length 1.
"""
ret = self.copy()
ret.x /= self.magnitude()
ret.y /= self.magnitude()
return ret
def magnitude(self):
return math.hypot(self.x, self.y)
so in your case, you might define a method like:
def complemented(self):
ret = self.copy()
ret.__invert__()
return ret
the copy module can make a copy of a instance exactly like you whish:
def __invert__(self):
ret = copy.deepcopy(self)
ret.complemented()
return ret
I think you mean implementation of Factory design pattern in Python example

In Python, can I bind a variable to a function/expression so that it automatically updates?

Let's say I've got a variable A that is the result of a function/expression F. F in it's turn has a number of other variables in it, let's say X,Y and Z.
Is it possible to bind A to F so that whenever X,Y or Z changes, A will be updated automatically?
What I want to avoid is that everytime X,Y and Z changes, I have to remember to update A explicitly in the code. I also don't want to call the function everytime I want to use the A.
Example (as per requested): I've got the following function:
def calcHits():
return sum(hitDiceRolls,level*modList['con'])
and in my program (outside of the function), I've got a variable called hitPoints (yes, it's a roleplaying game program). Whenever the variables that's used in the function is changed, I want hitPoints to change as well.
The typical way to do this in Python would be to use a class:
class ExpressionBinder:
def __init__(self, f):
self.f = f
self.x = 0
self.y = 0
self.z = 0
#property
def result(self):
return self.f(self.x, self.y, self.z)
You can use it like this:
def f(x, y, z):
return x**3 + y**2 + z
b = ExpressionBinder(f)
b.x = 1
b.y = 2
b.z = 3
print(b.result)
There is no way in Python to automatically rebind a name in global or local scope in response to other names being rebound. However, it should be possible to make a class that can keep track of some values and have a member function that returns the value you called A. And, as #Alok pointed out, you can use property descriptors to make a member name that implicitly calls a function to return its value, so you can hide the function and treat the name like a plain old name.
class Trk(object):
"""Track some values and compute a function if any change"""
def __init__(self, name, fn, **objects_to_track):
def _trk_fn(self):
if any(self.__dict__[x] != self.original_objects[x] for x in self.original_objects):
self.value = self.saved_fn(self.__dict___)
# now that self.value is updated, also update self.original_objects
for x in self.original_objects:
self.original_objects[x] = self.__dict__[x]
return self.value
self.original_objects = objects_to_track # make reference copy
self.__dict__.update(objects_to_track)
self.name = name
self.saved_fn = fn
self.fn = self._trk_fn()
self.value = self.fn()
I'm sorry but I am very tired right now, and I canot finish this example. I didn't test it either. But this shows one way to track values, and if they are different, do something different. You use it like this:
# want to track x, y, z
trk = Trk(x, y, z)
trk.fn() # returns up-to-date value
trk.x = new_value
trk.fn() #detects that trk.x changed and computes new trk.value
If the above works, you can use the property descriptor stuff to bind a name such that an attempt to read a value from the name will call self.fn()
EDIT: Oh, it's important that when self.value is updated, self.original_objects should be updated. I've added code to do that.
And now I'm going to sleep!

Categories

Resources