Python: Call for value inside nested class - python

I'm trying to call for value from class B that is nested in class A and use it in class C.
I'm getting AttributeError:
class A():
class B():
a = 1
class C():
b = 2
c = B.a + b
AttributeError: class B has no attribute 'a'
I also tried to call From 'A', Pycharm recognize it, but python still get AttributeError:
class A(object):
class B(object):
a = 1
class C(object):
b = 2
c = A.B.a + b
AttributeError: class A has no attribute 'B'
Does someone have an idea of how to use it?
Thanks

The problem is that the class template (A) is not constructed while you're calling A.B.a. That is, A is not bound yet to a class.
Try this workaround:
class A():
class B():
a = 1
Now create C separately (A is already defined):
class C():
b = 2
c = A.B.a + b
And reference C from A:
A.C = C
This can possibly be done via meta-classes, but could be an over-kill here.

At compile time, the class definition for class A is not complete hence you can not access the classes, variables and methods defined in a parent class inside a nested class.
You can try separating the class definitions though as suggested by #Reut Sharabani.

You can not access the class by its name, while the class definition statement is still executed.
class A(object):
class B(object):
a = 1
class C(object):
b = 2
c = A.B.a + b # here class A statement is still executed, there is no A class yet
To solve the problem you must defer the execution of those statements :
move the all those statements to a classmethod
call them after the classes was defined.
class A(object):
class B(object):
#classmethod
def init(cls):
cls.a = 1
class C(object):
#classmethod
def init(cls):
cls.b = 2
cls.c = A.B.a + cls.b
#classmethod
def init(cls):
cls.B.init()
cls.C.init()
A.init()

Related

How to access objects from a different class?

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"

Why I can't instantiate a instance in the same module?

Suppose my module is myclass.py, and here is the code:
#!/usr/bin/env python
# coding=utf-8
class A(object):
b = B()
def __init__(self):
pass
class B(object):
pass
and import it
In [1]: import myclass
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-e891426834ac> in <module>()
----> 1 import myclass
/home/python/myclass.py in <module>()
2 # coding=utf-8
3
----> 4 class A(object):
5 b = B()
6 def __init__(self):
/home/python/myclass.py in A()
3
4 class A(object):
----> 5 b = B()
6 def __init__(self):
7 pass
NameError: name 'B' is not defined
I know that if I define the class B above the class A, it is ok, there is no error. But, I don't want do that, are there any other methods to solve this. And I know that in C, there is function declaration.Thank you!
The class definition is a statement. When statement AA is executed, The statement of BB is not executed yet. Therefore, There is no class B yet and you get NameError: name 'B' is not defined
class A(object):
b = B() # <== AA
def __init__(self):
pass
class B(object): # <== BB
pass
To fix it:
You can change the order of classes:
class B(object):
pass
class A(object):
b = B()
def __init__(self):
pass
You can move the statement which use the class B to classmethod and call it after the the defintion of class B:
class A(object):
#classmethod
def init(cls):
cls.b = B()
def __init__(self):
pass
class B(object):
pass
A.init()
It should work if you do it like so:
class A(object):
def __init__(self):
self.b = B()
class B(object):
pass
EDIT: You can do it like this if you want to write all the definitions of the class after you have written class A.
class B:
pass
class A(object):
b = B()
def __init__(self):
pass
class B(object):
def __init__(self):
pass
EDIT 2: Ignore the above solution, it doesn't work.
Is there any good reason to do what you are doing? In general this is quite dangerous pattern in Python.
In your case
class A(object):
b = B()
def __init__(self):
pass
You are binding an instance of B to the class A, which means that every instance of class A will share the same instance of class B. It's a case you must then handle properly.
In general you don't want this, If you want each instance of A to be related to an instance of B, you must make the assignment inside __init__
class A(object):
def __init__(self):
self.b = B()
In these case it doesn't meter where class B is defined, since it's instantiated at run time.
Again beware that the semantic is very different in the two cases (if you know Java, the former is more like defining a static attribute).
About:
And I know that in C, there is function declaration
You shouldn't make too much parallels with a language like C, which is very different on many aspects, most important: it's a compiled language, that means that you code is parsed in it whole before being translated to machine language, that's why you can make function declaration and have your namespace populated regardless of the order you define things.
Python is an interpreted language, which means basically that each statement is translated when it's called and a class declaration is called when the module is imported.
So to recap: if you really need a class bound instance, you have to declare class B before class A, else you must instantiate B inside __init__, then you can declare B wherever you want (since it's called at runtime).

How can i have 2 classes reference the same instance of a class

I have class A class B and class C.
class A and B can affect class C. so they need to refer to the same instance of the class.
#a.py
from C import C
Cinstance = C()
Cinstance.add()
#b.py
class b(object)
#i need to refer to 'cinstance' here to control the same instance of the class
#C.py
class C(object)
def __init__(self):
self.a=1
def add(self):
self.a += 1
print a
How do i need to import and instanciate the classes for it to work this way? I am new to programming and still learning so things that are obvious are still a little difficult for me right now.
class A:
def __init__(self,cInst):
self.c = cInst
class B:
def __init__(self,cInst):
self.c = cInst
cInst = C()
a = A(cInst)
b = B(cInst)
something like that maybe
based on what you have there I think the easiest thing would be to import Cinstance from module a.
from a import Cinstance
You can pass an instance of A and B to your C.__init__ method and save them as attributes of C.
I'm on my phone, so the code below isn't tested
class C(object):
def __init__(self, a, b):
self.a = a
self.b = b
>>> c = C(A(), B())

How to copy a member function of another class into myclass in python?

I have a utility class from which I want to use one of the member function in another class. I don't want to inherit from that class. I just want to re-use the code from one of the member function of the other class. Kind of partial inheritance.
class HugeClass():
def interestedFunc(self,arg1):
doSomething(self.someMember1)
def OtherFunctions(self):
...
class MyClass():
def __init__(self):
self.someMember1 = "myValue"
self.interestedFunc = MagicFunc(HugeClass.interestedFunc)
c = MyClass()
print c.interestedFunc(arg)
Is there such a MagicFunc in python?
You can do what you want ie.:
class Foo(object):
def foo(self):
print self.a
class Bar(object):
foo = Foo.__dict__['foo']
b = Bar()
b.a = 1
b.foo()
But are you sure that this is good idea?
It seems like the __dict__ part from the older answer is not required in Python 3
This works fine:
class Foo:
def foo(self):
print self.a
class Bar:
foo = Foo.foo
b = Bar()
b.a = 1
b.foo()

Python object conversion

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

Categories