Class instance as class variable in python - python

I am making a class which I would like to have as a class member of a separate class so that all instances of this second class can access the first class. At the moment I have something which looks like this:
class A:
def __init__(self):
print "In Constructor!"
class B:
ClassA = ''
def __init__(self, InstanceA):
self.ClassA = InstanceA
However, I get complaints saying "str object has no attribute..." when I try and use the ClassA class variable. Is there a way to construct class B with an argument of InstanceA and then somehow set it to be a class variable? Or any other solution for that matter!

You are not assigning the class attribute in B.__init__, just setting a new instance attribute - B.ClassA is still '' (None would be a more sensible starting value, by the way).
The minimal fix is:
class B:
ClassA = None
def __init__(self, InstanceA):
self.__class__.ClassA = InstanceA # or B.ClassA = ...
However, note that this changes the class attribute every time you create a new instance.
Based on your comments, something like this may be more helpful:
class B:
ClassA = None
#classmethod
def set_class_attr(cls, instance):
cls.ClassA = instance
Which you can then use like:
B.set_class_attr(A()) # set class attribute once
b = B() # don't need to pass in new A instances when creating B instances
b.ClassA. # ...
Depending on the behaviour you want, you can check in that classmethod whether the instance has already been set and e.g. raise an error if the user tries to reset it.

Related

how to access the instance variables at class level in Python?

class A():
def __init__(self, name):
self.name = name
if self.name== "xyz":
print("Hi", self.name)
Here am getting an error - 'unresolved reference 'self'.
Can't we access the instance variables at the class level using self?
Your instance variable self.name is created when a class instance is created, is unique to the instance and is destroyed when the instance is being deleted. Any given class could have 0 to many millions of unique instances active at the same time. If you could somehow reference one of the instances, which would it choose?
During the definition of the class as in your example, there are 0 instances. In fact the class object itself has not been fully constructed and has not been assigned to the name A. So you couldn't get an instance with a self variable even if you wanted to.
You've only defined how an instance with a name variable would be created, you haven't actually created one.
Here are two ways to access the instance variables. The first is to access it directly in the constructor, which is fairly obvious. The second method is to keep track of all instances of the class, and then iterate through them and access the specific variable of each instance that you are interested in.
class A():
def __init__(self, name_):
self.name = name_
if self.name == "xyz":
print("Hi", self.name)
class B():
instances = []
def __init__(self, name_):
self.name = name_
self.instances.append(self)
a = A("xyz")
b = B("xyz")
for instance in B.instances:
if instance.name == "xyz":
print("Hi", instance.name)
Output:
Hi xyz
Hi xyz

Python linear inheritance, middle class being overridden by child class on super() property calls

I have a class setup like so:
class A(object):
__configuration = {}
def __init__(self, configuration: dict = {}):
A.__configuration = configuration
#property
def configuration(self):
return A.__configuration
class B(A):
def __init__(self, configuration: dict = {}):
super().__init__(configuration=configuration)
#property
def configuration(self):
return super().configuration.get('mammals')
class C(B):
def __init__(self, configuration: dict = {}):
super().__init__(configuration=configuration)
#property
def configuration(self):
return super().configuration.get('human')
Now here is where I am running into something that I can't quite get around.
When I instantiate class C, it will call the super init to class B. Then, class B in turn calls a super init to class A.
The configuration will get set as a class variable in class A, and the property method when called will return that configuration/dict/class variable.
Class B I am attempting to have the configuration property get the super (class A's) configuration, then retrieve the 'mammals' value from it.
Class C then in turn I am attempting to (when called from class C) get the 'human' value from it's parent, which will call the class B's property, which I hoped would in turn call the class A's property... Thus resulting in a key / value lookup of:
get entire config
get the mammal value (which is another config/dict)
get the human value (type doesn't matter)
Problem:
When I instantiate class C, it propagates up to class A on instantiation as it should. Class A's configuration is set correctly. Then, in class B, when I reference that super().configuration, it ends up returning my CHILD (class C) 's configuration.
For example, if I put this line in my init in class B and let the instantiation carry out from instantiation class C:
print(self.configuration)
it would return to me the value for the human dictionary, NOT the mammals dictionary which is what I would like it to.
Here is an example of a configuration I would pass in when instantiating Class C:
config = {
'mammals': {
'human': {
...
}
...
}
...
}
exampleInstantiation = C(configuration=config)
I have been trying to look up linear inheritance, the ordering for the class method resolutions but I can't find anything that is giving me insight on why the MIDDLE class is being overridden by the child class.
Any help is appreciated.

How to reference another nested class from within nested class

I have the following nested structure:
from peewee import *
class Parent:
...
class A:
name = TextField()
class B:
from_A = ForeignKeyField(A)
I am trying to reference class A within a ForeignKeyField within class B, but both A and Parent.A return a name not found error. What is the proper way to reference class A from within class B? Is this possible?
At the time of definition of class B, class Parent is not fully defined so it cannot be used: at definition time, you can only use:
global variables
variables belonging to the element being defined
But you have no access to variables defined in an enclosing block be them classes or not.
So you are left with only two options:
define class B outside of Parent
initialize the element at run time after everything has been defined (in that sense, run time starts immediately the end of the class Parent block`):
class Parent:
...
class A:
name = TextField()
class B:
...
Parent.B.from_A = ForeignKeyField(Parent.A)

Class instance as static attribute

Python 3 doesn't allow you to reference a class inside its body (except in methods):
class A:
static_attribute = A()
def __init__(self):
...
This raises a NameError in the second line because 'A' is not defined.
Alternatives
I have quickly found one workaround:
class A:
#property
#classmethod
def static_property(cls):
return A()
def __init__(self):
...
Although this isn't exactly the same since it returns a different instance every time (you could prevent this by saving the instance to a static variable the first time).
Are there simpler and/or more elegant alternatives?
EDIT:
I have moved the question about the reasons for this restriction to a separate question
The expression A() can't be run until the class A has been defined. In your first block of code, the definition of A is not complete at the point you are trying to execute A().
Here is a simpler alternative:
class A:
def __init__(self):
...
A.static_attribute = A()
When you define a class, Python immediately executes the code within the definition. Note that's different than defining a function where Python compiles the code, but doesn't execute it.
That's why this will create an error:
class MyClass(object):
a = 1 / 0
But this won't:
def my_func():
a = 1 / 0
In the body of A's class definition, A is not yet defined, so you can't reference it until after it's been defined.
There are several ways you can accomplish what you're asking, but it's not clear to me why this would be useful in the first place, so if you can provide more details about your use case, it'll be easier to recommend which path to go down.
The simplest would be what khelwood posted:
class A(object):
pass
A.static_attribute = A()
Because this is modifying class creation, using a metaclass could be appropriate:
class MetaA(type):
def __new__(mcs, name, bases, attrs):
cls = super(MetaA, mcs).__new__(mcs, name, bases, attrs)
cls.static_attribute = cls()
return cls
class A(object):
__metaclass__ = MetaA
Or you could use descriptors to have the instance lazily created or if you wanted to customize access to it further:
class MyDescriptor(object):
def __get__(self, instance, owner):
owner.static_attribute = owner()
return owner.static_attribute
class A(object):
static_attribute = MyDescriptor()
Using the property decorator is a viable approach, but it would need to be done something like this:
class A:
_static_attribute = None
#property
def static_attribute(self):
if A._static_attribute is None:
A._static_attribute = A()
return A._static_attribute
def __init__(self):
pass
a = A()
print(a.static_attribute) # -> <__main__.A object at 0x004859D0>
b = A()
print(b.static_attribute) # -> <__main__.A object at 0x004859D0>
You can use a class decorator:
def set_static_attribute(cls):
cls.static_attribute = cls()
return cls
#set_static_attribute
class A:
pass
Now:
>>>> A.static_attribute
<__main__.A at 0x10713a0f0>
Applying the decorator on top of the class makes it more explicit than setting static_attribute after a potentially long class definition. The applied decorator "belongs" to the class definition. So if you move the class around in your source code you will more likely move it along than an extra setting of the attribute outside the class.

Initialize object properties as class properties first in Python

I have the habit to initialize the properties of an instance of a class in the constructor of that class but, in case the properties are very tight to the class, I also declare them and initialize them to None ([] or some other base value) as properties in the class.
For instance:
class AClass(object):
aprop = None
def __init__(self):
self.aprop = "avalue"
Which in most of the cases it won't make much of a difference from just doing:
class AClass(object):
def __init__(self):
self.aprop = "avalue"
However, if somebody gets the scope of the AClass will notice that an instance of this class is expected to have an attribute named aprop. I think of it as a placeholder for the property aprop in the class.
This looks to me more as a question of style, but I would like to know whether this is a good practice. Would you recommend it? Is it something common? or should I try to get rid of it?
When you do self.aprop = "avalue" in the __init__ function, every instance of AClass will have the aprop property since __init__ is called when you initiate an instance. This makes aprop an instance variable.
When you do aprop = None you add a class variable to AClass. This means that the class itself will have this property.
For Example:
>>> class AClass(object):
... def __init__(self):
... self.aprop = "avalue"
...
>>> AClass.aprop
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'AClass' has no attribute 'aprop'
And:
>>> class AClass(object):
... aprop = None
... def __init__(self):
... self.aprop = "avalue"
...
>>> AClass.aprop
>>> print AClass.aprop
None
So if you want your class to have this property you should define it as a class variable. If you only use it in instances, the only case you should define a class property is if you don't always redefine it (hide it) in __init__:
class AClass(object):
aprop = None
def __init__(self):
self.bprop = "bvalue"
Unless you ever access the property on the class itself (e.g. as AClass.aprop) rather than on an instance, there's no need to make it a class member if you always populate it on an instance in the __init__ method.
My vote is to always write the least amount of code necessary to clearly convey the intent. Adding an extra member to the class obscures the intent (since your actual goal here is for it to be an instance property) and is unnecessary: that sounds like two strikes against it.

Categories

Resources