How can I set a class variable from inside a function inside another function?
var.py
class A:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def seta(self):
def afunction():
self.a = 4
afunction()
def geta(self):
return self.a
run.py
cA = A()
print cA.a
cA.seta()
print cA.a
print cA.geta()
python run.py
1
1
1
why does a not equal 4 and how can I make it equal 4?
Edit:
Thanks everyone - sorry, I just saw now. I accidentally was off by a _ in one of my names.... so my scope is actually all ok.
The problem is that there are multiple self variables. The argument passed into your inner function overwrites the scope of the outer.
You can overcome this by removing the self parameter from the inner function, and making sure you call that function in some way.
class A:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def seta(self):
def afunction(): # no self here
self.a = 4
afunction() # have to call the function
def geta(self):
return self.a
As others have mentioned, afunction is never called. You could do something like this:
class A:
def __init__(self):
self.a = 1
def seta(self):
def afunction(self):
self.a = 4
afunction(self)
def geta(self):
return self.a
a = A()
print a.a
a.seta()
print a.a
Here we actually call afunction and explicitly pass it self, but this is a rather silly way to set the attribute a -- especially when we can do it explicitly without the need for getters or setters: a.a = 4
Or you could return the function:
def seta(self):
def afunction(): #Don't need to pass `self`. It gets picked up from the closure
self.a = 4
return afunction
and then in the code:
a = A()
a.seta()() #the first call returns the `afunction`, the second actually calls it.
Inside seta, you define a function
def afunction(self):
self.a = 4
...that would set self.a to 4 if it would ever be called. But it's not called anywhere, so a is unchanged.
As several others have said, you need to actually call functiona at some point. Comments won't let me type this intelligably so here's an answer:
def seta(self):
def functiona(self): #defined
self.a = 4
functiona() #called
How can you make it equate to 4:
class A:
def __init__(self):
self.a = 1
self.b = 2
self.c = 3
def seta(self):
##def afunction(self): (remove this)
self.a = 4
def geta(self):
return self.a
Tricky part: Why does is not equate to 4...
Currently a is set to 4 only via "afunction". Since afunction is never called it never executes.. The seta has "afunction" nested inside but not called... similar to member variables within a classs.
Related
class myclass():
def fun(self):
a = 12
return a
b = fun()
TypeError: fun() missing 1 required positional argument: 'self'
The idea is to be able to use b inside another def, like
class myclass():
def fun(self):
a = 1
return a
b = fun()
def fun2(self):
c = self.b + 2
Is this possible?
Since myclass.fun is an instance method, if you want to cache its result you should do that in an instance attribute (defined in __init__) rather than a class attribute.
class myclass():
def __init__(self):
self.b = self.fun()
def fun(self):
a = 1
return a
def fun2(self):
c = self.b + 2
This question already has answers here:
Python: Bind an Unbound Method?
(5 answers)
Closed 3 years ago.
Let us suppose the following situation: I have a class with some initial values. Furthermore, I want to provide the possibility to pass an user-defined method, when initializing a new object. The user knows about the attributes of the class in advance and may want to consider them in the function, for instance:
class some_class():
def __init__(self, some_method):
# some initial values
self.a = 8
self.b = 12
# initializing a new object with a user-specific method
self.some_method = some_method
def some_method(self):
pass # this method shall be specified by the user
# user-specific function
def some_function():
return self.a + self.b
some_object = some_class(some_method = some_function)
print(some_object.some_method())
Of course, the given example does not work, but I hope it shows what I want to do. I am searching for a way to define a function outside the class, which refers to the attribute of an object after it was passed during initialization.
What I try to avoid is to solve the problem with fixed name conventions, for instance:
class some_class():
def __init__(self, some_method):
self.a = 8
self.b = 12
self.some_method = some_method
def some_method(self):
pass
def some_function():
return some_object.a + some_object.b # -> fixed names to avoid the problem
some_object = some_class(some_method = some_function)
print(some_object.some_method())
I think what I need is a kind of placeholder or alternative to self. Does anybody has an idea?
This works, although not sure it is the most elegant way to achieve what you want:
class some_class():
def __init__(self, some_method):
self.a = 8
self.b = 12
self.some_method_func = some_method
def some_method(self):
return self.some_method_func(self)
def some_function(self):
return self.a + self.b
some_object = some_class(some_method = some_function)
print(some_object.some_method())
If I'm reading this right, then the easy option is just to do the following:
class some_class():
def __init__(self):
self.a = 8
self.b = 12
def some_method(self):
pass
def my_method(self):
return self.a + self.b
# Redefine the class method
some_class.some_method = my_method
# Or, if you only want to do it for a specific instance:
instance = some_class()
instance.some_method = my_method
The usual way to do this 'properly' though is with sub-classing.
You need to get the class and the caller of the class to agree to a contract. The contract is that the class will pass in the instance of the class to the function, and the function must accept that as an argument.
class some_class():
def some_method(self):
return self.some_method_func(self)
def some_function(obj):
return obj.a + obj.b
I have a need to allow the user to define a function that processes data in an object (the wisdom and security implications in this have been discussed at length in another question and would just be duplicate comments here.)
I'd like the function to act just like any other method. That is
def my_method(self):...
Would be invoked with:
obj_handle.my_method()
I almost have this achieved below except that the function that results need to be explicitly passed self as an argument, rather than receiving it as the first argument as is typical for a method.
You can see this in property p where I have the odd self.process(self) call.
I imagine that I need to provide something to exec that is like the globals() dictionary, but I'm not certain of several things:
Is this correct?
What is the equivalent of globals() in a class?
Does this solve the problem? If not what do I need to do?
So the question is, how do I get an exec() defined function to act as an object's method?
class test:
def __init__(self, a, b):
self.a=a
self.b=b
#property
def p(self):
return self.process(self)
def set_process(self,program):
func_dict={}
proc_fun = exec(program,func_dict)
setattr(self,'process',func_dict['process'])
def process(self):
return self.a+self.b
t=test(1,2)
prog = '''\
def process(self):
return self.a * self.b
'''
t.set_process(prog)
t.p
Answered in #juanpa.arrivillaga's comment above:
Set the function on the class if you want its descriptor protocol to work and bind tye instance when called on an instance. So one solution just make your set_process a classmethod. – juanpa.arrivillaga 1 hour ago
Working result
class test:
def __init__(self, a, b):
self.a=a
self.b=b
#property
def p(self):
return self.process()
#classmethod
def set_process(cls,program):
func_dict={}
proc_fun = exec(program,func_dict)
setattr(cls,'process',func_dict['process'])
def process(self):
return self.a+self.b
t=test(1,2)
prog = '''\
def process(self):
return self.a * self.b
'''
test.set_process(prog)
t.p
If you want to operate on instances rather than classes:
import types
class Test:
def __init__(self, a, b):
self.a = a
self.b = b
#property
def p(self):
return self.process()
def set_process(self, program):
d = dict()
exec(program, d)
self.process = types.MethodType(d["process"], self)
def process(self):
return self.a + self.b
prog = '''\
def process(self):
return self.a * self.b
'''
t = Test(1, 2)
t.set_process(prog)
print(t.p)
t = Test(1, 2)
print(t.p)
class A:
def __init__(self):
self.i = 0
def demo(self):
self.a=1
class B(A):
def __init__(self, j = 0):
super().__init__()
self.j = j
print(self.i)
self.demo()
def demo(self):
print(self.a)
def main():
b = B()
print(b.i)
print(b.j)
main()
why am i not able to access self.a inside class b
does prefixing a variable with self. will make it an instance variable
Thanks
When you include a demo method for both classes, the most recently-defined one masks the others. Since you define B after you define A but before you call any of the methods in A, demo will try to access a variable that was never defined. You should either call demo within A (in __init__, probably), or change the name of demo in B to something unique, which will allow you to access both methods (probably the best approach, since they do different things and you want to make use of both).
Because you overwrite demo method on B class.
If you want to access self.a add it to __init__ method of A class or call parent demo method like this:
def demo(self):
super().demo()
print(self.a)
It is because instance variable b is not initiated within __init__ of A
Because class A.demo() is not executed:
class A:
def init(self):
self.i = 0
def demo(self):
self.a=1
class B(A):
def __init__(self, j = 0):
super().__init__()
self.j = j
print(self.i)
super().demo()
self.demo()
def demo(self):
print(self.a)
def main():
b = B()
print(b.i)
print(b.j)
main()
Have written a simple code like this:
class Operations:
#global a,b
a=1
b=2
def __init__(self):
print(self,"object has been created")
def add(self):
#a = 2
#b = 3
return a+b
obj1=Operations()
sum=obj1.add()
print(sum).
when i run this code, am getting this error NameError: name 'a' is not defined.
can you please explain why variables a and b are not accessible in the method 'add' which is defined in the same class?
Note:when am declaring variables as a global, am able to access the variables inside the 'add' method.
You need to use the self keyword.
What does self do?
a = 1
class Operations:
a = 2
def fun1(self):
return a
def fun2(self):
return self.a
obj = Operations()
print(obj.fun1())
print(obj.fun2())
Output:
1
2
Solution for you case:
class Operations:
a=1
b=2
def __init__(self):
print(self,"object has been created")
def add(self):
return self.a + self.b
obj1=Operations()
print(obj1.add())
Output:
<__main__.Operations object at 0x100663588> object has been created
3
Use the class reference
Value= self.a + self.b
Is this the answer that you need? if you're writing a class, use self.value instead global value:
class Operations:
def __init__(self):
self.a = 1
self.b = 2
print(self, "object has been created")
def add(self):
return self.a + self.b
obj1 = Operations()
print(obj1.add())