Python - how to get class instance reference from an attribute class? - python

class A()
att = B()
class B()
...
a = A()
b = B()
a.att = b
How can b get reference of a ? I need to get an attribute of a here.
Thanks!

You can make a generic "Reference()" class, that keep any reference of itself in an attributes dictionnary.
class Reference(object):
def __init__(self):
self.references = {}
def __setattr__(self, key, value):
if hasattr(self, 'references'):
if isinstance(value, Reference):
if not key in value.references:
value.references[key] = []
value.references[key].append(self)
elif value is None and hasattr(self, key):
old = getattr(self, key).references
if key in old and self in old[key]:
old[key].remove(self)
super(Reference, self).__setattr__(key, value)
And then, create your classes :
class A(Reference):
def __init__(self):
super(A, self).__init__()
self.att = None
class B(Reference):
def __init__(self):
super(B, self).__init__()
self.att = None
And use it :
a = A()
b = B()
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {}
a.att = b
print 'A references', a.references
print 'B references', b.references
# A references {}
# B references {'att': [<__main__.A object at 0x7f731c8fc910>]}
At the end, you'll have back reference to all Reference class from any properties

Easiest way would be to just add an extra function parameter to the method in B that needs A, and pass it through when called. Or, just make B's init take an A as argument, and change the bit in A's init to be att = B(self)

class A(object):
def __init__(self):
self.att = B(self)
class B(object):
def __init__(self, a):
self.a = a
a = A()
a.att.a is a
Or another way,
class A(object):
def __init__(self, b):
b.a = self
self.att = b
class B(object):
pass
a = A(B())
a.att.a is a

This code doesn't make a lot of sense... but if I correctly understand your question...
class A(object):
pass #or whatever you like
class B(object):
def __init__(self, ref): #accept one argument
self.ref = ref
a = A()
b = B(a) #pass `a` as that argument
a.att = b
Might be one answer.

class A(object):
def __init__(self):
self._att=None
#property
def att(self):
return self._att
#att.setter
def att(self, value):
self._att = value
value.parent = self
class B(object):
pass
a = A()
b = B()
a.att = b
print b.parent

Related

Python: pass whole self of class to init of new class

I have a class and a sub-class, I'd like to pass the whole of the self of the class to the sub-class. I can pass self over to the new class explicitly easily enough, e.g.
class foo:
def __init__(self, a, b):
self.a = a
self.b = b
self.c = 'foo'
def foo_method(self):
print('a foo method')
class bar(foo):
def __init__(self, foo_object):
self.a = foo_object.a
self.b = foo_object.b
self.c = foo_object.c
def bar_method(self):
print('a bar method')
foo_object = foo(a = 'a', b = 'b')
bar_object = bar(foo_object)
bar_object.a
Is there a more succinct way to pass these over? Something like:
class bar(foo):
def __init__(self, foo_object):
self = self.foo_object
Update:
Thanks https://stackoverflow.com/users/10104112/bastien-antoine, the following solution worked:
class bar(foo):
def __init__(self, foo_object):
self.__dict__ = foo_object.__dict__.copy()
def bar_method(self):
print('a bar method with ' + str(self.c))
Have you tried the copy builtins library?
Otherwise I think you can easily implement your own .copy() method that would copy the values from the old object __dict__ to the new one. Something like this:
class MyObject:
a = None
def set_default_values(self):
self.a = 1
def copy(self, old):
if type(self) == type(old):
self.__dict__ = old.__dict__.copy()
else:
raise TypeError('Wrong type')
if __name__ == "__main__":
obj_1 = MyObject()
print(obj_1.a)
obj_1.set_default_values()
print(obj_1.a)
obj_2 = MyObject()
print(obj_2.a)
obj_2.copy(obj_1)
print(obj_2.a)
Note that I've added a type checking to be sure that you copy attributes that would exist otherwise, but I think simply self.__dict__ = old.__dict__.copy() would work fine, thought you might end up with attributes you might not suppose to have in the new object.
Hope this helps!
I think that you can do that with
class bar(foo):
def __init__(self):
super(bar, self).__init__()
with this code, you ran the init function for the subclass

Scoped metaclasses; or changing class variable of class A during the __init__ of class B containing nested classes inheriting from A?

Consider the code below:
class A(object):
attr = None
def __init__(self):
assert A.attr is not None
class B(object):
def __init__(self, attr):
A.attr = attr
class C(A):
def __init__(self):
super().__init__()
class D(A):
def __init__(self):
super().__init__()
nested_classes = {cls.__name__: cls for cls in {C, D}}
Above doesn't seem to work as I intend because:
>>> first_class = B("first")
>>> first_sub_class = first_class.C()
>>> first_sub_class.attr
'first'
>>> second_class = B("second")
>>> second_sub_class = second_class.C()
>>> second_sub_class.attr
'second'
>>> first_sub_class.attr
'second'
Is there a way to have first_sub_class.attr be first while having second_sub_class.attr be second? Possibly by having a metaclass whose scope is within B?
A few points:
I don't want to pass attr around, I want to set it while B is being initialized.
I don't want to circumnavigate the point above by using partial, since it breaks the rest of the code relying on __name__ or __qualname__ or alike.
I want to keep faithful to the current structure as much as possible.
To solve this problem just add the line self.attr = self.attr inside the __init__ function of A. Since you don't want to change the attributes of A, you will have to make the following changes:
class A(object):
attr = None
def __init__(self):
assert self.attr is not None # Don't refer to A, but to self to get the correct value
self.attr = self.attr
class B(object):
def __init__(self, attr):
self.attr = attr # Don't edit A, just save the value in own instance
def __getattribute__(self, item): # completely added, does some magic to ensure class.attr is set correctly
if item in B.nested_classes:
c = B.nested_classes[item]
c.attr = self.attr
return c
return super().__getattribute__(item)
class C(A):
def __init__(self):
super().__init__()
class D(A):
def __init__(self):
super().__init__()
nested_classes = {cls.__name__: cls for cls in {C, D}}
first_class = B("first")
first_sub_class = first_class.C()
print(first_sub_class.attr)
second_class = B("second")
second_sub_class = second_class.C()
print(second_sub_class.attr)
print(first_sub_class.attr)
You're insanely overcomplicating this:
class A:
def __init__(self, attr):
self.attr = attr
class C(A):
pass
class D(A):
pass
class B:
def __init__(self, attr):
self.attr = attr
def C(self):
return C(self.attr)
def D(self):
return D(self.attr)
Behaves exactly as desired:
>>> first_class = B("first")
>>> first_sub_class = first_class.C()
>>> first_sub_class.attr
'first'
>>> second_class = B("second")
>>> second_sub_class = second_class.C()
>>> second_sub_class.attr
'second'
>>> first_sub_class.attr
'first'

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"

python classes dependant on eachother, how to init?

I have two classes:
class A(object):
def __init__(self, b):
self b = b
class B(object):
def __init__(self, a):
self a = a
I'd like to init them like this:
a = A(b)
b = B(a)
But I can't since 'b' doesn't exist when doing a = A(b). I have to do:
a = A()
b = B(a)
b.a = a
But that seems unclean. Is this solvable?
You could either make one class instantiate the other:
class A(object):
def __init__(self):
self.b = B(self)
class B(object):
def __init__(self, a):
self.a = a
a = A()
b = a.b
Or make one class tell the other about itself, like this:
class A(object):
def __init__(self, b):
self.b = b
b.a = self
class B(object):
def __init__(self):
#Will be set by A later
self.a = None
b = B()
a = A(b)

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