I want to print(read or use) the changing variable self.tt in B().check() while class A is changing self.tt, is it any way to do it or other better solution to achieve the task?
class A:
def __init__(self):
self.tt = 0
def change_tt(self):
for i in range(100000000):
self.tt += 1
sleep(1)
class B():
def __init__(self):
self.x = A.tt
def check(self):
while True:
print(self.x)
a = A()
b = B()
x1 = threading.Thread(target=A.change_tt)
x2 = threading.Thread(target=B.check)
x1.start()
x2.start()
AttributeError: type object 'A' has no attribute 'tt'
There are a couple of things going on here. The biggest issue is that you can't access an instance attribute from the class. A secondary issue is that integers are immutable.
Here is some code that should fix both:
class A:
def __init__(self):
self.tt = 0
def change_tt(self):
for i in range(100000000):
self.tt += 1
sleep(1)
class B():
def __init__(self, a):
self.a = a
def check(self):
while True:
print(self.a.tt)
a = A()
b = B(a)
x1 = threading.Thread(target=a.change_tt)
x2 = threading.Thread(target=b.check)
x1.start()
x2.start()
Notice that the code of class A remains unchanged. However, it's important to understand that it is being used differently. A is the class object. It has attributes that are functions, but no integers. When you create instance a, the functions become methods when you access them with the . operator. a also has an attribute tt.
A thread target should be a no-arg callable. The functions A.change_tt and B.check both require a single positional argument, self. However, the bound methods a.change_tt and b.check are no-arg callables. The process of binding a function to an instance with the . operator creates a wrapper that passes in self automatically.
When you do self.tt += 1, the object that is the previous value of tt is unbound from tt and possibly garbage collected. Integers are immutable, which means that what really happens here is self.tt = self.tt + 1. That means that the statement self.x = A.tt in B.__init__ is unreasonable even if tt existed in A. x would be a reference to the object that is the initial value of tt, and would keep referring to that object even as tt changed to the incremented version.
An instance of B needs to know about the object that A.tt refers to currently. One way to do that is to pass a reference to B.__init__. That's why we define __init__(self, a), and invoke B as B(a) to get an instance that refers to a.
Related
I have two questions regarding the code below.
What is the difference between self.a=self.test1() and a=self.test1()? One is class field and other one is object field?
Why cannot I define result = self.a+self.b? How to correct it?
class Test():
def __init__(self):
self.a=self.test1()
a=self.test1()
self.b=Test.test2()
result = self.a+self.b
def test1(self):
a=100
return a
#classmethod
def test2(cls):
b=200
return b
#staticmethod
def test3():
print("Testing3 is calling ")
c=500
return c
self.a = self.test1() creates an instance attribute named a. The attribute will be accessible from the object anywhere you have a reference to the object.
a = self.test1() defines a local variable named a. It will go out of scope once __init__ returns.
result = self.a + self.b doesn't work because it is in a context where self is not defined. self is just the (conventional) name of the first parameter of an instance method. It's not defined in the namespace of the class statement itself.
self.a is a property in this class. It will remain accessible throughout functions in the Test() class. a = self.test1(), however, goes away once __init__(self) finishes, because a is local to __init__(self).
For result = self.a + self.b, I assume you want a variable called result calculated after self.a and self.b is defined? At that indentation level a statement like this is usually not allowed (I could be wrong), usually a declaration of a property of a class happens here.
I want to have a counter which increments every time a subclass is instantiated. How would I achieve this such that the last statement below evaluates to True:
class Abstract(ABC):
counter = 0
class A(Abstract):
pass
class B(Abstract):
pass
a = A()
b = B()
a.counter += 1
b.counter == 1
Currently each subclass gets its own counter, rather than sharing the one outlined in the superclass.
Would this work for you?
global_counter = 0
class Abstract:
def __init__(self):
global global_counter
global_counter += 1
class A(Abstract):
def __init__(self):
super().__init__()
class B(Abstract):
def __init__(self):
super().__init__()
a = A()
b = B()
print(global_counter) # (output: 2)
So I've implemented several different ways to achieve what I wanted:
Using a global keyword as suggested by #nihilok
Creating a custom Counter class to handle the integer value (essentially a fancy int).
using an int type in the super class and having its methods directly reference it using the super class's name instead of simply using the cls passed in during a class method.
My favourite (least amount of extra parts and most canonical to how I tend to write my objects) was the last method. Where the above translates to something like:
lass Abstract(ABC):
counter = 0
#staticmethod
def increment():
Abstract.counter += 1. # instead of cls.counter += 1
class A(Abstract):
pass
class B(Abstract):
pass
a = A()
b = B()
a.increment()
b.increment()
a.counter == b.counter # now true.
I'd like to create a class that has 2 input attributes and 1 output attribute such that whenever one of the input attributes are modified the output attribute is modified automatically
I've tried defining the attributes as instance variables within and outside the constructor function but in either case, after instantiating the object, the output attribute remains fixed at the value set at the moment of instantiation
class Example():
def __init__(self,n):
self.name=n
inA=1
inB=1
if inA==1 and inB==1:
outA=1
else:
outA=0
when instantiated outA is set to 1 as expected
but if I try to update:
object.inA=0
object.outA remains 1 whereas I need it to be updated to 0
Trying to avoid the use of functions if possible. New to python and OOP so sorry if this question is nonsensical or has an obvious answer
If you want instance attributes that depend on other instance attributes, properties are the way to go.
class Example:
def __init__(self, n):
self.name = n
self.inA = 1
self.inB = 1
#property
def outA(self):
return self.inA and self.inB
You access outA like a regular instance attribute, obj.outA.
>>> my_obj = Example("example")
>>> my_obj.outA
1
Changing the attributes inA and inB affect outA.
>>> my_obj.inA = 0
>>> my_obj.outA
0
You can create a function in the class and some other minor changes:
class Example():
def __init__(self,n):
self.name=n
self.inA=1
self.inB=1
def f(self):
if self.inA==1 and self.inB==1:
self.outA=1
else:
self.outA=0
To call it:
a = Example('foo')
a.inA = 0
a.f()
print(a.outA)
Output:
0
As you can see, taking out:
a.f()
line would make it give an error:
AttributeError: 'Example' object has no attribute 'outA'
Do you want it to return your output?
Expanding on U9-Forward's answer:
class Example():
def __init__(self,n):
self.name = n
self.inA = 1
self.inB = 1
def f(self):
return self.inA and self.inB
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.
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()