Access a Class object from a class static variable in python3? - python-3.x

Is it possible to access a class object or its inner class object from a class static variable in python3?
class OuterClass:
all_subclasses = {
# is it possible to access the OuterClass from a class static variable
'innerclass1': OuterClass.InnerClass1
}
#classmethod
isInnerClass(cls, identifier: str):
return identifier.lower() in cls.all_subclasses
class InnerClass1:
def __init__(self):
pass
If not, what will be alternative for this?

You can refer to attributes of the class directly in the class definition, as long as the reference comes after the definition:
class A:
class B:
pass
x = B
print(A.x)
# <class '__main__.A.B'>
This has some caveats. For reasons that are very complicated, you can't use class attributes directly in a comprehension in the class definition:
class A:
class B:
pass
x = [B for _ in range(5)] # NameError: name 'B' is not defined
You also can't refer to the class itself in it's own definition:
class A:
x = A # NameError: name 'A' is not defined
This is because class definition is basically another way of creating a type object
class A:
x = 1
A = type('A', (object,), {'x': 1})
And it makes total sense both that you can't use an object before it's created and that you can't refer to it by a name it hasn't been assigned to yet.
It's important to note that this all applies only to the class definition itself, that is to say all of the code that gets executed directly as the class is created. Code that gets executed later, like method definitions, can refer to the class like any other code or through type(self)

Related

Python pro way to make an abstract class allowing each child class to define its own attributes, Python3

I have to model several cases, each case is realised by a class. I want to make sure that each class must have 2 methods get_input() and run(). So in my opinion, I can write a CaseBase class where these 2 methods are decorated as #abstractmethod. Therefore, any child class has to implement these 2 methods. And this is exactly my goal.
However, due to the nature of my work, each case is for distinct subject, and it is not easy to define a fixed group of attributes. The attributes should be defined in the __init__ method of a class. That means I don't know what exactly attributes to write in the CaseBase class. All I know is that all children cases must have some common attributes, like self._common_1 and self._common_2.
Therefore, my idea is that I also decorate the __init__ method of CaseBase class by #abstractmethod. See my code below.
from abc import ABC, abstractmethod
from typing import Dict, List
class CaseBase(ABC):
#abstractmethod
def __init__(self):
self._common_1: Dict[str, float] = {}
self._common_2: List[float] = []
...
#abstractmethod
def get_input(self, input_data: dict):
...
#abstractmethod
def run(self):
...
class CaseA(CaseBase):
def __init__(self):
self._common_1: Dict[str, float] = {}
self._common_2: List[float] = []
self._a1: int = 0
self._a2: str = ''
def get_input(self, input_data: dict):
self._common_1 = input_data['common_1']
self._common_2 = input_data['common_2']
self._a1 = input_data['a1']
self._a2 = input_data['a2']
def run(self):
print(self._common_1)
print(self._common_2)
print(self._a1)
print(self._a2)
def main():
case_a = CaseA()
case_a.get_input(input_data={'common_1': {'c1': 1.1}, 'common_2': [1.1, 2.2], 'a1': 2, 'a2': 'good'})
case_a.run()
if __name__ == '__main__':
main()
My question: Is my way a good Python style?
I followed many Python tutorials about how to make Abstract class and child class. They all give examples where a fixed group of attributes are defined in the __init__ method of the base class. I also see some approach to use super().__init__ code in the child class to change the attributes defined in the base class or to add new attributes. But I am not sure if it is better (more pro) than my way.
Thanks.
You mostly used the abc module in python 3.10 correctly. but it doesn't make sense to decorate the constructor with #abstractmethod. It's unnecessary. Each class, derived or not, can and will have its own constructor. You can call super().__init__(args) within the child class to call the constructor of its immediate parent if you didn't want to duplicate its code but wanted to do further initialization in the child class constructor.

Accessing class variables using class or object?

What is the best practice / difference between accessing a class variable using the class or using a object created by the class?
for example I have the following class and creating an object:
class MyClass():
class_variable = 10
def __init__(self):
self.object_variable = 5
object = MyClass()
I can access the class_variable in two ways:
object.class_variable
myClass.class_variable
I cannot see any difference as these two possibilities will always return the same value.

python class not recognize class declared inside of her

this question must be a stupid one but important one and couldn't find any discussion about this in stackoverflow.
I'm trying to declare a class (lets say class 'B') inside another class (lets say 'A'), and use that class('B') in a method of class 'A', but for some reason in python you cannot declare an object member of class type that is declared in the same class.
why is that the case? in C you can access to the inner class from a method of the outside class without any problem...
(my intention that is only class A will ever need a member of type class B and i want only A to be able to find out that such a class like B...)
what is the proper way to do so in python?
class A:
def __init__(self):
self.B_object = B() # error 'unresolved refernace B'
class B:
def __init(self):
pass
class A:
def __init__(self):
self.B_object = A.B()
class B:
def __init(self):
pass
Try this
if you want to make B class private you can try this
class A:
def __init__(self):
self.__B_object = A.__B()
class __B:
def __init__(self):
pass

Check whether an instance of a class exists at runtime

I need to know how to check if an instance of a given class exists at runtime. So I need to make interactions between this instance and other classes. There is no relationship between these classes (composition, aggregation, and inheritance). So how do you get the reference for this class if it exists?
If you just want to know if (or how many times) a class has been instantiated, just keep a counter in the class:
class Foo:
counter = 0
def __init__(self):
Foo.counter += 1
Foo()
print(Foo.counter)
Alternatively, if you want to keep a handle on all the instances (by reference), instead store self:
class Foo:
classes = []
def __init__(self):
Foo.classes.append(self)
Foo()
print(Foo.classes[0])

Python 3 metaclass defined functions not visible in the class derived from metaclass

I am working on a python 3 based metaclass, as i understand metaclass a typedef
of a class. Here is a small example
class smallClass(type):
def __init__(self, clsname, bases, clsdict):
super(smallClass, self).__init__(clsname, bases, clsdict)
self.a = 10
self.b = 15
print(self.addnos())
def addnos(self):
return self.a + self.b
def __new__(self, clsname, bases, clsdict):
return super(smallClass, self).__new__(self, clsname, bases, clsdict)
class smallClass2(object, metaclass=smallClass):
la = smallClass.addnos
clstest = smallClass2()
clstest.addnos() ''' this does not work: AttributeError: 'smallClass2' object has no attribute 'addnos' '''
strange thing is function addnos is not visible from smallClass2 even it is based on metaclass smallClass that included addnos function
can someone help to understand how to access functions defined in metaclass? Or why clstest.addnos() does not work?
Function addnos can be accessed from metaclass but not from derived class, why?
Here another alternative try, have the same problem
class smallClass(type):
def __init__(self, clsname, bases, clsdict):
super(smallClass, self).__init__(clsname, bases, clsdict)
self.a = 10
self.b = 15
print(self.addnos())
def addnos(self):
return self.a + self.b
def __new__(self, clsname, bases, clsdict):
return super(smallClass, self).__new__(self, clsname, bases, clsdict)
class smallClass2(object, metaclass=smallClass):
pass
clstest = smallClass2()
clstest.addnos()
I can't understand what is your intention, and whether you really need a metaclass at all. But here is what is happening:
A metaclass in Python is a class-object class. I think it is easy to visualize that with an example on the (iPython) terminal :
In [1]: class A:
...: pass
...:
...: a = A()
...:
In [2]: type(a)
Out[2]: __main__.A
In [3]: type(A)
Out[3]: type
In this case, "A", returned by type(a) is the class of the object "a", and "type" returned by "type(A)" is the class of the object "A" - the trick is that in Python even classes are objects: they are all instances of "type" or of a subtype of "type". This role of "class of a class" is what is termed "metaclass".
When ou inherit from "type", instances of the class ou create will be classes themselves. And there is syntactic support of the language, in the form of the "named parameter" on the class statement, to select the metaclass for a class body.
All that said, this is how attribute retrieval works in Python (shortened version - I won't enter into "descriptors" or the setattr, getattr and getattribute mechanisms which add a lot of steps):
When you request an attribute from an object, Python first(*) looks into that object's __dict__ attribute, which must be mapping, if it contains the requested attribute. If not, it looks for the attribute on the object's class (on the class __dict__ as well). If the class of the object does not have the attribute, Python looks for it on the superclasses of the object - but it does not step into the class'class to look for the attribute. (It follows the metaclasses as they endup in the class __mro__ attribute).
So, if I do:
class MyMeta(type):
test = "value from metaclass"
other_test = "Other metaclass value"
class A:
test = "value from ancestor class"
class B(A, metaclass=MyMeta):
pass
b = B()
For the instance "b", Python can find "test" as defined in "A", but it will never automatically find the "test" as defined in "MyMeta", nor it will see "other_test". This is what is taking place in your code.
If one needs to see from an instance values as they are defined in the metaclass, all one have to do is to step through the class - so, if a method in B wants to get to "other_test" above, this will work:
class B(A, metaclass=MyMeta):
def method(self):
print(self.__class__.other_test)
(Not that test, however would still be shadowed by the test defined in the ancestor class in A)
All said, I find it very little probable that you actually need a metaclass for whatever you are trying there. It looks more like you want the behavior for simple class inheritance.
(*) Always having in mind this is a super-simplifed description of the attribute lookup algorithm. The first lookup for an attribute is actually in the instance's class itself, looking for a "descriptor" object.

Resources