I have a class Foo which is instantiated an indefinite number of times during my program sequence. Like so:
def main():
f = Foo()
while f.run():
del f
f = Foo()
with run() being a method that runs an decisive condition for keeping the program alive.
Now, my Foo class creates on its __init__ method two objects a and b:
Foo class
class Foo:
def __init__(self):
a = A()
b = B(a.var)
I'm looking for a way to a being declared only at the first Foo instantiation and use that same first-instantiated a at the other Foo instantiations.
Problem arises because b depends on a. I thought about a couple solutions - from playing with __new__ and __init__ to override __del__ and global variable as cache - but none of them worked.
note: A needs to be at the same module as Foo
Maybe using a class variable?
class Foo:
a = None
def __init__(self):
if not Foo.a:
Foo.a = A()
b = B(Foo.a.var)
And function B needs to check whether a is None.
If I understand you correctly, you should be able to just make a a class variable.
class Foo:
a = A()
def __init__(self):
b = B(Foo.a.var)
I'm afraid some of your requirements will make Foo extremely difficult to test. Instead, I would suggest that you move some of the dependencies from your constructor to a start class method that would be responsible for creating the initial A instance (at the same module as Foo) and then reusing that instance in a refresh method.
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
#classmethod
def start(cls):
a = A()
b = B(a.var)
return cls(a, b)
def refresh(self):
b = B(self.a.var)
return self.__class__(self.a, b)
Then, your main function would look something like:
def main():
f = Foo.start()
while f.run():
f = f.refresh()
By overwriting the f variable, you are effectively deleting the reference to the old instance which will eventually be garbage collected.
Related
Is there a way in python to pass a function call to an inner object, maybe through a decorator or wrapper? In the example below, class A holds a list of class B objects, and one of the class B objects is selected as the active object. I want class A to function as a passthrough, just identifying which of the class B objects that the call goes to. However, class A doesn't know what type of class it is going to hold beforehand, so I can't just add a set_var function to class A. It has to work for any generic function that class B has. It will only have one type of class in its objects list, so it could take class B as an input when it is instantiated and dynamically create functions, if that's a possibility. The client wouldn't know whether it's dealing with class A or class B. The code below is as far as I got.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, object):
self.objects.append(object)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
You could use the generic __getattr__ to delegate to the wrapped object.
class A:
def __init__(self):
self.objects = []
self.current_object = 0
def add_object(self, obj):
self.objects.append(obj)
self.current_object = obj
def __getattr__(self, name):
return getattr(self.current_object, name)
class B:
def __init__(self):
self.var = 10
def set_var(self, new_var):
self.var = new_var
a_obj = A()
b_obj1 = B()
b_obj2 = B()
a_obj.add_object(b_obj1)
a_obj.add_object(b_obj2)
a_obj.set_var(100)
print(b_obj2.var)
That will print "100".
You will still get an AttributeError if the wrapped object doesn't have the expected method.
It was interesting to look at this, it is intentionally rough but it does indeed allow you to call one the B instance's set_var methods.
The code below uses sets as a quick and dirty way to see the difference in callable methods, and if there is; it sets the attribute based on that name. Binding the method to the A instance.
This would only bind set_var once from the first object given.
def add_object(self, object):
self.objects.append(object)
B_methods = set([m for m in dir(object) if callable(getattr(object, m))])
A_methods = set([m for m in dir(self) if callable(getattr(self, m))])
to_set = B_methods.difference(A_methods)
for method in to_set:
setattr(self, method, getattr(object, method))
I have something like this (I know this code doesn't work, but it's the closer to what I want to achieve):
class A:
def __init__(self):
self.a = 'a'
def method(self, a=self.a):
print a
myClass = A()
myClass.method('b') # print b
myClass.method() # print a
What I've done so far, but I do not like it, is:
class A:
def __init__(self):
self.a = 'a'
def method(self, a=None):
if a is None:
a = self.a
print a
myClass = A()
myClass.method('b') # print b
myClass.method() # print a
Default arguments are evaluated at definition time. By the time the class and method are defined self.a is not.
Your working code example is actually the only clean way of achieving this behavior.
The default is evaluated at method definition time, i.e. when the interpreter executes the class body, which usually happens only once. Assigning a dynamic value as default can only happen within the method body, and the approach you use is perfectly fine.
I want to use the variables i have declared inside a function in one class, in another class.
For example i want to use the variable "j" in another class. Is it possible? (I read somewhere that it might have something to do with instance variables but fully couldn't understand the concept).
class check1:
def helloworld(self):
j = 5
class check1:
def helloworld(self):
self.j = 5
check_instance=check1()
print (hasattr(check_instance,'j')) #False -- j hasn't been set on check_instance yet
check_instance.helloworld() #add j attribute to check_instance
print(check_instance.j) #prints 5
but you don't need a method to assign a new attribute to a class instance...
check_instance.k=6 #this works just fine.
Now you can use check_instance.j (or check_instance.k) just like you would use any other variable.
This may seems a little bit like magic until you learn that:
check_instance.helloworld()
is completely equivalent to:
check1.helloworld(check_instance)
(If you think about it a little bit, that explains what the self parameter is).
I'm not completely sure what you're trying to achieve here -- There are also class variables which are shared by all instances of the class...
class Foo(object):
#define foolist at the class level
#(not at the instance level as self.foolist would be defined in a method)
foolist=[]
A=Foo()
B=Foo()
A.foolist.append("bar")
print (B.foolist) # ["bar"]
print (A.foolist is B.foolist) #True -- A and B are sharing the same foolist variable.
j cannot be seen by another class; however, I think you meant self.j, which can.
class A(object):
def __init__(self, x):
self.x = x
class B(object):
def __init__(self):
self.sum = 0
def addA(self, a):
self.sum += a.x
a = A(4)
b = B()
b.addA(a) # b.sum = 4
Using class inheritane it is very easy to "share" instance variables
example:
class A:
def __init__(self):
self.a = 10
def retb(self):
return self.b
class B(A):
def __init__(self):
A.__init__(self)
self.b = self.a
o = B()
print o.a
print o.b
print o.retb()
Dealing with classes (nested etc) does not look easy in Python, surprisingly! The following problem appeared to me recently and took several hours (try, search ...) without success. I read most of SO related links but none of them has pointed the issue presented here!
#------------------------------------
class A:
def __init__(self):
self.a = 'a'
print self.a
class B(A):
def __init__(self):
self.b = 'b'
A.a = 'a_b'
print self.b, A.a
#------------------------------------
class C:
class A:
def __init__(self):
self.a = 'a'
print self.a
class B(A):
def __init__(self):
self.b = 'b'
A.a = 'a_b'
print self.b, A.a
#------------------------------------
#------------------------------------
>>> c1 = A()
a
>>> c1.a
'a'
>>> c2 = B()
b
>>> c2.a, c2.b
('a_b', 'b')
>>> c3 = C()
>>> c4 = c3.A()
a
>>> c4.a
'a'
>>> c5 = c3.B()
b a_b
>>> c5.b
'b'
>>> c5.a
Traceback (most recent call last):
File "", line 1, in
AttributeError: B instance has no attribute 'a'
Where is the problem in the code?
AND
In both cases it seems that when B(A) is initialized A() is not initialized. What is the solution for this issue? Note that the term A.__init__() being called inside B()'s __init__() does not work!
Updates:
class Geometry:
class Curve:
def __init__(self,c=1):
self.c = c #curvature parameter
print 'Curvature %g'%self.c
pass #some codes
class Line(Curve):
def __init__(self):
Geometry.Curve.__init__(self,0) #the key point
pass #some codes
g = Geometry()
C = g.Curve(0.5)
L = g.Line()
which results in:
Curvature 0.5
Curvature 0
what I was looking for.
The code executed in a method runs in the local scope of that method. If you access an object that is not in this scope, Python will look it up in the global/module scope, NOT in the class scope or the scope of any enclosing class!
This means that:
A.a = 'a_b'
inside C.B.__init__ will set the class attribute of the global A class, not C.A as you probably intended. For that you would have to do this:
C.A.a = 'a_b'
Also, Python will not call parent methods if you override them in subclasses. You have to do it yourself.
The scoping rules mean that if you wanted to call the __init__ method of the parent class inside C.B.__init__, it has to look like this:
C.A.__init__(self)
and NOT like this:
A.__init__(self)
which is probably what you've tried.
Nested classes seems so unpythonic, even if considered as factories. But to answer your question: There simply is no c5.a (instance of C.B). In the init-method of C.B you add to the CLASS C.A an attribute a, but not to C.B! The class A does already have an attribute a, if instantiated! But the object of class B (and even the class) doesn't!
You must also keep in mind, that __init__ is not an constructor like in C++ or Java! The "real constructor" in python would be __new__. __init__ just initializes the instance of a class!
class A:
c = 'class-attribute'
def __init__(self):
self.i = 'instance-attribute'
So in this example c is a class-attribute, where i is an attribute of the instance.
Even more curios, is your attempt to add an attribute to the baseclass at the moment of the instantiation of the child-class. You are not getting a "late" inheritance-attribute that way.
You simply add to the class A an additional attribute, which surprises me to even work. I guess you are using python 3.x?
The reason for this behaviour? Well, i guess it has to do with pythons neat feature that in python definitions are executed(AFAIK).
The same reason why:
def method(lst = []):
is almost ever a bad idea. the deafult-parameter gets bound at the moment of the definition and you won't generate a new list-object every-time you call the method, but reusing the same list-object.
class foo():
def __init__(self)
self.var1 = 1
class bar():
def __init__(self):
print "foo var1"
f = foo()
b = bar()
In foo, I am doing something that produces "var1" being set to 1
In bar, I would like to access the contents of var1
How can I access var1 in the class instance f of foo from within the instance b of bar
Basically these classes are different wxframes. So for example in one window the user may be putting in input data, in the second window, it uses that input data to produce an output. In C++, I would have a pointer to the caller but I dont know how to access the caller in python.
As a general way for different pages in wxPython to access and edit the same information consider creating an instance of info class in your MainFrame (or whatever you've called it) class and then passing that instance onto any other pages it creates. For example:
class info():
def __init__(self):
self.info1 = 1
self.info2 = 'time'
print 'initialised'
class MainFrame():
def __init__(self):
a=info()
print a.info1
b=page1(a)
c=page2(a)
print a.info1
class page1():
def __init__(self, information):
self.info=information
self.info.info1=3
class page2():
def __init__(self, information):
self.info=information
print self.info.info1
t=MainFrame()
Output is:
initialised
1
3
3
info is only initialised once proving there is only one instance but page1 has changed the info1 varible to 3 and page2 has registered that change.
No one has provided a code example showing a way to do this without changing the init arguments. You could simply use a variable in the outer scope that defines the two classes. This won't work if one class is defined in a separate source file from the other however.
var1 = None
class foo():
def __init__(self)
self.var1 = var1 = 1
class bar():
def __init__(self):
print var1
f = foo()
b = bar()
Same as in any language.
class Foo(object):
def __init__(self):
self.x = 42
class Bar(object):
def __init__(self, foo):
print foo.x
a = Foo()
b = Bar(a)
Alternatively you could have a common base class from which both derived classes inherit the class variable var1. This way all instances of derived classes can have access to the variable.
Something like:
class foo():
def __init__(self)
self.var1 = 1
class bar():
def __init__(self, foo):
print foo.var1
f = foo()
b = bar(foo)
You should be able to pass around objects in Python just like you pass around pointers in c++.
Perhaps this was added to the language since this question was asked...
The global keyword will help.
x = 5
class Foo():
def foo_func(self):
global x # try commenting this out. that would mean foo_func()
# is creating its own x variable and assigning it a
# value of 3 instead of changing the value of global x
x = 3
class Bar():
def bar_func(self):
print(x)
def run():
bar = Bar() # create instance of Bar and call its
bar.bar_func() # function that will print the current value of x
foo = Foo() # init Foo class and call its function
foo.foo_func() # which will add 3 to the global x variable
bar.bar_func() # call Bar's function again confirming the global
# x variable was changed
if __name__ == '__main__':
run()