I thought that this code would work
class A:
def __init__(self):
self.x = 1
B = self.create_b()
print(B.y)
def create_b(self):
class B:
def __init__(self):
self.y = self.x
return B
A = A()
but I receive the following error
AttributeError: type object 'B' has no attribute 'y'
What am I doing wrong?
You're confusing classes with class instances (not Python modules). In Python class statements are executable and create a callable object that you must then be called to create instance objects of the class that was defined.
Regular methods of a class automatically receive a first argument that's the instance they belong to, and by convention, this argument is usually called self.
Here's what I mean:
class A:
def __init__(self):
self.x = 1
B = self.create_b() # Create B class.
b = B(self) # Create instance of B class passing this instance of A.
print(b.y)
def create_b(self):
class B:
def __init__(self, a_inst):
self.y = a_inst.x
return B
a = A() # -> 1
There are three problems with this code. The first is that since create-b returns a class object, not an instance of the class, B's __init__ was never run. You could solve this with
class A:
def __init__(self):
self.x = 1
B = self.create_b()
b = B()
print(b.y)
def create_b(self):
class B:
def __init__(self):
self.y = self.x
return B
A = A()
The second is that nested classes do not have access to the wrapping method's local namespace like a nested function (closure) would. When attempting self.y = self.x, instances of class B have no special relationship with the instance of A that created them. You could solve this with
class A:
def __init__(self):
self.x = 1
B = self.create_b(self)
b = B()
print(b.y)
def create_b(self):
class B:
def __init__(self, a):
self.y = a.x
return B
A = A()
The third is that python creates a weakref to classes when they are defined that never goes away. Each time you call create_b, you create a small memory leak. You could solve this with
class A:
def __init__(self):
self.x = 1
b = B(self)
print(b.y)
class B:
def __init__(self, a):
self.y = a.x
A = A()
Related
I have two classes. class A has a public variable X, which is used by both classes,
class A changes the value of X every 3 seconds, while class B prints the new value of X. But the class B sees the initial value 10 only. I need class B to see the change of the variable X in Class A.
import threading
import time
class A():
X = 10
def __init__(self):
self.first()
def first(self):
while True:
self.X = self.X + 3
print("A",self.X)
time.sleep(3)
class B(A):
def __init__(self):
t = threading.Thread(target= self.second, args=())
t.setDaemon(True)
t.start()
def second(self):
while True:
print(self.X)
time.sleep(3)
example1 = B()
example2 = A()
This is not setting the class variable X.
self.X = self.X + 3
On the first iteration self.X is reading the class variable since there is no instance variable X.
However it assigns the instance variable and from that point on, self.X within A is an instance variable and any changes made are not reflected in A.X.
You can fix this by making the first argument of the method (self) refer to the class and not the instance with the #classmethod decorator.
#classmethod
def first(cls):
while True:
cls.X = cls.X + 3
print("A",cls.X)
time.sleep(3)
Full code:
import threading
import time
class A():
X = 10
def __init__(self):
self.first()
#classmethod
def first(cls):
while True:
cls.X = cls.X + 3
print("A",cls.X)
time.sleep(3)
class B(A):
def __init__(self):
t = threading.Thread(target= self.second, args=())
t.setDaemon(True)
t.start()
def second(self):
while True:
print(self.X)
time.sleep(3)
example1 = B()
example2 = A()
You can access its parent's X, A's x, by either using: A.x or super().x
It doesn't work the way you think it should work. The objects A() and B() are not the same as classes A and B. The objects are separated instances. When you change x using object A(), object B() doesn't know anything about the change that happened. And it couldn't.
If you need it to work the way you want, you should add A() into b's initializer. And then call the variable of A() object.
class B:
def __init__(self, A_instance):
self.a = A_instance
def working(self):
x = self.a.x
I'm a newbie in python. I have a class X inheriting class Y. In class X the attribute b allways
keep constant and never change but in the class Y it must change when a given
condition is satisfied.
class X(object):
def __init__(self,others_attributes):
self.b = 1
self.others_attributes = others_attributes
class Y(X):
def __init__(self,others_attributes,variable_condition):
super(X, self).__init__(others_attributes)
self.b += 1
How can ensure that each simulation step any instance of the class Y will have a specific value of the attribute b? Shall I create a #classmethod or a #properties similar to something like below?
Or is there a better strategy?
if variable_condition:
self.b = self.b + 1
else:
self.b = self.b
return self.b
Not sure if you're asking about maintaining class level state or instance level state.
If you're asking about how to change class level state all you need to do is store b as a class variable:
some_condition = True
class X(object):
count = 0
class Y(X):
def __init__(self):
if some_condition:
Y.count += 1
instances = [
X(),
Y(),
Y(),
X(),
X(),
Y()
]
print('\n'.join([str(i.count) for i in instances]))
If you want to change the b for only certain instances of Y then you could do something like:
class X(object):
def __init__(self):
self.b = 0
class Y(X):
def __init__(self, some_condition):
super(Y, self).__init__()
if some_condition:
self.b += 1 # or set it to whatever else you want
else:
self.b = -1
instances = [
X(),
Y(True),
Y(False),
X(),
X(),
Y(True)
]
print('\n'.join([str(i.b) for i in instances]))
#kingkupps
considering as bellow
some_condition = True
class X(object):
def __init__(self,a,c):
self.b = 1
self.a = a
self.c = c
class Y(X):
def __init__(self,a,c):
super(X,self).__init__(a,c)
def __init__(self, some_condition):
super(Y, self).__init__()
if some_condition:
self.b += 1 # or set it to whatever else you want
else:
self.b = -1
File "C:\Users\Alexandre\Documents\PYTHON\Paper_ICESP\teste.py", line 248, in ABM
cells.myfun(a,c)
File "C:\Users\myname\firstfolder\secondfolder\thirdfolder\myscript.py", line 132, in myfun
c = Y(a,c)
File "C:\Users\myname\firstfolder\secondfolder\thirdfolder\myscript.py", line 154, in init
super(X,self).init(a,c)
TypeError: object.init() takes exactly one argument (the instance to initialize)
I suspect that creating a superclass Y inside daughter class Y is interfering in Y. What do you think?
As you can see the code, I have a super class bar_for_foo_mixin() and I have a subclass myfoo(bar_for_foo_mixin): I am computing a operation self.Z = X+Y in bar() method of superclass.
Now I want the self.z = 0 updated to the computation done in bar() method and inheirt this value to the subclass myfoo(bar_for_foo_mixin): and use it inside subclass.
class bar_for_foo_mixin():
def __init__(self):
self.z = 0
def bar(self, q):
x = 2
y = 8
self.z = x + y + q
class oldfoo():
def __init__(self):
pass
var = bar_for_foo_mixin()
var.bar(10)
class myfoo(bar_for_foo_mixin):
def __init__(self):
super(myfoo, self).__init__()
def hello(self):
print("hello", self.z)
final = myfoo()
final.hello()
Result of the code:
hello 0
Expected result:
hello 20
The bar_for_foo_mixin instance stored in your oldfoo.var class variable is a completely separate instance from the myfoo object you instantiated in the main program, so their instance variable z would not be shared.
If you would like a variable to be shared across all instances of a class, you should make it a class variable instead, and make methods that are dedicated to updating class variables, such as bar_for_foo_mixin.bar, a class method instead:
class bar_for_foo_mixin():
z = 0
#classmethod
def bar(cls, q):
x = 2
y = 8
cls.z = x + y + q
class oldfoo():
def __init__(self):
pass
var = bar_for_foo_mixin()
var.bar(10)
class myfoo(bar_for_foo_mixin):
def __init__(self):
super(myfoo, self).__init__()
def hello(self):
print("hello", self.z)
final = myfoo()
final.hello()
This outputs:
hello 20
You're not even calling the bar method by the new final variable:
class bar_for_foo_mixin():
def __init__(self):
self.z = 0
def bar(self, q):
x = 2
y = 8
self.z = x + y + q
class myfoo(bar_for_foo_mixin):
def __init__(self):
super(myfoo, self).__init__()
def hello(self):
print("hello", self.z)
final = myfoo()
final.bar(10) # <== call it to take effect
final.hello() # ==> hello 20
There are three classes :
A, B and C
The __init__ of B creates an object of A. Using the mutators, I will be able to change the attributes of A from B for the instance created.
However, I am not unable to find any way to use that instance of A created by B to be used in C without passing the Object explicitly to the __init__ method [ not C.__init(self, object: A) ]
Is there any way to implicitly allow C to use that instance of A ?
I am new to python and not sure if this a valid question. I have looked at other sources where it explicitly passes the object to class C
class A:
def __init__(self):
x = []
y = []
class C :
def __init__(self):
#[get obj1 without passing the instance in init]
self.value = None
def method1():
self.value = len([]) #len(obj1 of A.x)
class B:
def __init__(self):
obj1 = A()
obj1.x = [1,2,3,4]
obj1.y = [1,2,3]
obj2 = B()
print(obj2.value) #this should be the length of x in the instance A created above
Here is a simple example:
class A:
def __init__(self, i = ""):
self.item = i
class B:
def __init__(self):
self.a = A("hello")
class C:
def __init__(self):
b = B()
print(b.a.item)
c = C()
Output:
hello
Let's say we have classes A and B:
class A:
def hello_world(self):
print("hello world")
class B:
def __init__(self):
self.a = A()
def hello_world(self):
self.a.hello_world()
You create an instance of class B (which will create an instance of class A inside):
b = B()
You can then pass a reference to either b or b.a to any function of an instance of class C (either a constructor or not)
class C:
def hello_world(self, a):
a.hello_world()
c = C()
c.hello_world(b.a)
You can also use global variables:
class C:
def hello_world(self):
b.a.hello_world()
c = C()
c.hello_world()
Here the instances of class C will rely on variable b to be in place and just use its a attribute.
Using global variables in classes is generally considered to be hard to maintain and a bad practice. If your class depends on a value or an instance of some class you should pass the reference in the constructor (__init__ function) or in the function that's using it.
If these classes are in different different python files then you can also use these classes by importing the class name and creating an object of that class:
eg:
file1.py
class A:
def __init__(self):
x = []
y = []
file2.py
from file1 import A
class C :
def __init__(self):
[get obj1 without passing the instance in init]
self.value = None
self.obj_a = A()
def xyz(self):
print "in class c"
file3.py
from file2 import C
from file1 import A
Class B:
def __init__(self):
self.obj_a = A()
self.obj_c = C()
def another_func(self):
print self.obj_c.xyz()# it will print "in class c"
Assume that we have an object k of type class A. We defined a second class B(A). What is the best practice to "convert" object k to class B and preserve all data in k?
This does the "class conversion" but it is subject to collateral damage. Creating another object and replacing its __dict__ as BrainCore posted would be safer - but this code does what you asked, with no new object being created.
class A(object):
pass
class B(A):
def __add__(self, other):
return self.value + other
a = A()
a.value = 5
a.__class__ = B
print a + 10
a = A() # parent class
b = B() # subclass
b.value = 3 # random setting of values
a.__dict__ = b.__dict__ # give object a b's values
# now proceed to use object a
Would this satisfy your use case? Note: Only the instance variables of b will be accessible from object a, not class B's class variables. Also, modifying variables in a will modify the variable in b, unless you do a deepcopy:
import copy
a.__dict__ = copy.deepcopy(b.__dict__)
class A:
def __init__(self, a, b):
self.a = a
self.b = b
class B(A):
def __init__(self, parent_instance, c):
# initiate the parent class with all the arguments coming from
# parent class __dict__
super().__init__(*tuple(parent_instance.__dict__.values()))
self.c = c
a_instance = A(1, 2)
b_instance = B(a_instance, 7)
print(b_instance.a + b_instance.b + b_instance.c)
>> 10
Or you could have a sperate function for this:
def class_converter(convert_to, parent_instance):
return convert_to(*tuple(parent_instance.__dict__.values()))
class B(A):
def __init__(self, *args):
super().__init__(*args)
self.c = 5
But using the 2nd method, I wasn't able to figure out how to pass additional values