Create class instance within a class - python

I have a nested class in python for instance:
class A():
def __init__(self, attr1):
self.attr1 = attr1
class B():
def __init__(self, attr2):
self.attr2 = attr2
What I want to achieve is that instance b for class B, will be like a data structure of instance a for class A
However, it seems that b is not associate with a.
How can I achieve that?
Update:
What I want to do is something like the picture shown below, which is a java program object initialization:
It seems that user contains userID and Password and it is associated with the serviceOrder object.

There is rarely any reason to nest classes in Python. I think what you mean is to have an instance of B as an attribute of an instance of A, which is easy to do:
class A():
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.b = B(attr2)
class B():
def __init__(self, attr2):
self.attr2 = attr2

In all likelihood your preferred solution has already been provided in Daniel Roseman's answer.
However, if for some reason you or someone else really does need to nest class B inside of A, you can do that this way:
class A():
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.b = A.B(attr2) # NOTE: refer to class B via ``A.B``
class B():
def __init__(self, attr2):
self.attr2 = attr2
The reason you have to do it this way is B is a class attribute of A. It is no different than any other class-level attribute, and therefore accessing the attribute must be done via the owning class, e.g.:
MyClass.my_attr
# OR:
getattr(MyClass, 'my_attr')
# OR:
MyClass.__dict__['my_attr']
# etc. etc.
Note this is true even when you're inside of the owning class:
class MyClass():
class_attr = 1
def get_class_attr(self):
# return class_attr would raise a NameError
return MyClass.class_attr # no error
MyClass().get_class_attr() # 1

Related

Setting self as an instance from another class doesn't work [Python]

Let's assume I have a class A and a class B.
class A:
def __init__(self):
self.variable1 = 1
self.variable2 = 'sometext'
class B:
def __init__(self, inst):
self = inst
print(self.__dict__.keys(), inst.__dict__.keys())
The print function returns
b = B(inst)
dict_keys(['variable1', 'variable2']) dict_keys(['variable1', 'variable2'])
However when I try
b.variable1
It returns the following error
AttributeError: 'B' object has no attribute 'variable1'
In my more complex code I need almost all variable from class A in class B.
I tried using class inheritance however I couldn't make it work with class methods and constructors.
Is there a reason why the above method doesn't work?
Thx
You're trying to overwrite self, but that only works while you're in the init. Instead, try assigning the inst to a variable of the class B:
class B:
def __init__(self, inst):
self.inst = inst
print(self.__dict__.keys(), inst.__dict__.keys())
Now you can access the variables of class A via:
inst = A()
b = B(inst)
b.inst.variable1
Not sure what you're trying to achieve here exactly, but you could also initiate the class A object inside the init of class B instead of passing the object to class B.
To use variable from class A in B you have to access to class A from B. Then execute class B
class A:
variable1 = 1
variable2 = 'sometext'
class B:
def __init__(self, inst=None):
self.f1 = A().variable1
self.f2 = A().variable2
def get_var(self):
print (self.f1)
B().get_var()

How do I initialize the parent class using a class method instead of calling the constructor?

I have class A which I want to inherit from, this class has a class method that can initialize a new instance from some data. I don't have access to the code for from_data and can't change the implementation of A.
I want to initialize new instances of class B using the same data I would pass to the A's from_data method. In the solution I came up with I create a new instance of A in __new__(...) and change the __class__ to B. __init__(...) can then further initialize the "new instance of B" as normal. It seems to work but I'm not sure this will have some sort of side effects.
So will this work reliably? Is there a proper way of achieving this?
class A:
def __init__(self, alpha, beta):
self.alpha = alpha
self.beta = beta
#classmethod
def from_data(cls, data):
obj = cls(*data)
return obj
class B(A):
def __new__(cls, data):
a = A.from_data(data)
a.__class__ = cls
return a
def __init__(self, data):
pass
b = B((5, 3))
print(b.alpha, b.beta)
print(type(b))
print(isinstance(b, B))
Output:
5 3
<class '__main__.B'>
True
It could be that your use-case is more abstract than I am understanding, but testing out in a REPL, it seems that calling the parent class A constructor via super()
class A:
# ...
class B(A):
def __init__(self, data):
super().__init__(*data)
b = B((5, 3))
print(b.alpha, b.beta)
print(type(b))
print(isinstance(b, B))
also results in
5 3
<class '__main__.B'>
True
Is there a reason you don't want to call super() to instantiate a new instance of your child class?
Edit:
So, in case you need to use the from_data constructor... you could do something like
#... class A
class B(A):
def __init__(self, data):
a_obj = A.from_data(data)
for attr in a_obj.__dict__:
setattr(self, attr, getattr(a_obj, attr))
That is really hacky though... and not guaranteed to work for all attrs of A class object, especially if the __dict__ function has been overloaded.

What is the correct docstring documentation for self variable passed to another class

If I have two classes A and B where the object of the first class passes its self to the second class like below. What do I say is the type of that self variable when I perform Numpy/SciPy style docstring documentation? Is object the correct way to put it?
class A:
def __init__(self):
# Some data
def create_B(self):
new_B = B(self)
class B:
"""
This is the class for B
...
Attributes
----------
A : object
Refers to the object of class A that created B
"""
def __init__(self, A):
self.A = A

Initializing a class that consist of many classes in such a way that one of the classes has different attributes

Here are the classes and their relations:
http://i.imgur.com/HS5YrZZ.png
Code for clarification:
class A(object):
def __init__(self):
self.atr = 1
class B(object):
def __init__(self):
self.atr = A()
class C(object):
def __init__(self):
self.atr = A()
class D(object):
def __init__(self):
self.atr1 = B()
self.atr2 = C()
test1 = D()
Now what do I do if I want to initialize D in such a way that A's self.atr = 2, and that change reflects to all those classes (B and C) that use A as well when I initialize D
Like I imagine it in pseudo code:
test2 = D(A.self.atr = 2)
So you initialize D in such a manner that A's self.atr = 2
If you want B and C to have different properties, as required by a call from D, the way to do that is to pass parameters for the initialization of B and C so that they know what to do.
The parameter can be itself an instance of A, where the attributes you care for are set before inistantiatin B and C:
class A(object):
def __init__(self, atr=1):
self.atr = atr
class B(object):
def __init__(self, config):
self.atr = config
class C(object):
def __init__(self, config):
self.atr = config
class D(object):
def __init__(self):
my_a = A(2)
self.atr1 = B(my_a)
self.atr2 = C(my_a)
test1 = D()
update
I see from the comments above you seem to dislike this approach duew to the impression you'd have a lot of repetitive code everywhere -
That is not the case however - if for example, you have a lot of classes that have to be "preconfigured" like class A, passed to a lot of other classes, you could just create a bundle of all classes pre-configured - you'd still pass on a single parameter to each instance you create.
Also, there are, as you want, mechanisms in Python to allow dynamically reconfiguring classes - using "variables" being one of them - the probelm is that doing it in this naive way you want, you'd ahve pretty soon an unmaintainable mess.
For example, if you just use a module-level (= global) variable for "1" instead of hardcoding it into A, you could do:
CURRENT_ATR_VALUE = 1
class A(object):
def __init__(self):
self.atr = CURRENT_ATR_VALUE
class B(object):
def __init__(self):
self.atr = A()
class C(object):
def __init__(self):
self.atr = A()
class D(object):
def __init__(self, atr):
global CURRENT_ATR_VALUE
old = CURRENT_ATR_VALUE
CURRENT_ATR_VALUE = atr
self.atr1 = B()
self.atr2 = C()
CURRENT_ATR_VALUE = old
test1 = D(atr=2)
This would have thge exact effect you are intending, could not be simpler - whithout requiring any of the Language's advanced introspection capabilities, and still would lead you soon to an unmaintainable mess. The way passing parameters around does contain the custom values in the scopes they are wanted, without side-effects, not even in a multi-threading or multi-processing running environment, and is far more recomendable.
If you really want to mess things around, you could create a factory function that would produce a new class "A" with the desired attributes, and inject it in the module global namespace as a new "A" class while you instantiate the others - that would be "fancier" and maybe is what you'd like. Just write A inside something like:
def A_factory(atr=1):
class A(object):
def __init__(self, atr=1):
self.atr = atr
globals()["A"] = A
# creates default "A" class
A_factory(1)
And call this factory with your desired "atr" while instantiating "B" and "C" as above. This is absolutely unmanageable, but it is ultimately what you are asking for. T

Accessing outer class methods from an inner class

I want a python class that has a nested class where the inner class can access the members of the outer class. I understand that normal nesting doesn't even require that the outer class has an instance. I have some code that seems to generate the results I desire and I want feedback on style and unforeseen complications
Code:
class A():
def __init__(self,x):
self.x = x
self.B = self.classBdef()
def classBdef(self):
parent = self
class B():
def out(self):
print parent.x
return B
Output:
>>> a = A(5)
>>> b = a.B()
>>> b.out()
5
>>> a.x = 7
>>> b.out()
7
So, A has an inner class B, which can only be created from an instance of A. Then B has access to all the members of A through the parent variable.
This doesn't look very good to me. classBdef is a class factory method. Usually (and seldomly) you would use these to create custom classes e.g. a class with a custom super class:
def class_factory(superclass):
class CustomClass(superclass):
def custom_method(self):
pass
return CustomClass
But your construct doesn't make use of a customization. In fact it puts stuff of A into B and couples them tightly. If B needs to know about some A variable then make a method call with parameters or instantiate a B object with a reference to the A object.
Unless there is a specific reason or problem you need to solve, it would be much easier and clearer to just make a normal factory method giving a B object in A instead of stuff like b = a.B().
class B(object):
def __init__(self, a):
self.a = a
def out(self):
print self.a.x
class A(object):
def __init__(self,x):
self.x = x
def create_b(self):
return B(self)
a = A()
b = a.create_b()
b.out()
I don't think what you're trying to do is a very good idea. "Inner" classes in python have absolutely no special relationship with their "outer" class, if you bother to define one inside of another. It is exactly the same to say:
class A(object):
class B(object):
pass
as it is to say:
class B(object): pass
class A(object): pass
A.B = B
del B
That said, it is possible to accomplish something like what you're describing, by making your "inner" class into a descriptor, by defining __get__() on its metaclass. I recommend against doing this -- it's too complicated and yields little benefit.
class ParentBindingType(type):
def __get__(cls, inst, instcls):
return type(cls.__name__, (cls,), {'parent': inst})
def __repr__(cls):
return "<class '%s.%s' parent=%r>" % (cls.__module__,
cls.__name__, getattr(cls, 'parent', None))
class B(object):
__metaclass__ = ParentBindingType
def out(self):
print self.parent.x
class A(object):
_B = B
def __init__(self,x):
self.x = x
self.B = self._B
a = A(5)
print a.B
b = a.B()
b.out()
a.x = 7
b.out()
printing:
<class '__main__.B' parent=<__main__.A object at 0x85c90>>
5
7

Categories

Resources