Get name of class another class is instantiated inside of in Python - python

Is it possible to get the name of a python class in another class that was instantiated inside the first class.
Let me give you an example.
class SubClass:
top_level_name = None # name class it is instantiated in e.g. TopLevelClass
class TopLevelClass:
subclass = SubClass()
I understand that I can write the following...
class SubClass:
def __init__(self, class_name):
self.top_level_name = class_name
class TopLevelClass:
subclass = SubClass(class_name)
def __init__(self):
self.class_name = self.__class__.__name__
However, it would be nice to do it without needing to pass the class name as an argument when the class is initialized.
Is this possible, just wishful thinking, or a really bad idea for some reason I have not thought of yet.

I would suggest revisiting the design for these two classes. Having the instantiated class be aware of the calling class violates design principals of encapsulation and abstraction. It also creates a cyclic dependency (in this case only a logical dependency as only the name of the class is known). If you're using the class name as some kind of identifier for the instantiated class, you can pass in an id string in the constructor as you have in your example.

Related

In Python how to call Parent class function as if I were Parent object

I have a Parent and a Child class, both should execute their own fct in init but Child have to execute first the Parent fct :
class Parent(object):
def __init__(self):
self.fct()
def fct(self):
# do some basic stuff
class Child(Parent):
def __init__(self):
super().__init__()
self.fct()
def fct(self):
# add other stuff
Problem is that super().init() calls the Child fct and not the Parent one as I would like. Of course I could rename Child function as fct2 but I was wondering if I can do what I want to do without changing names (because fct and fct2 do the same thing conceptually speaking, they just apply on different things). It would be nice if I could call super().__init() as if were Parent object.
The idea of subclassining is this: if you ever need to use a method to the parent class, just do not create it in the child class.
Otherwise, in a hierarchy with complicated classes and mixins, and you really need the methods to have the same name, there is the name mangling mechanism, triggered by Python when using two underlines __ as a method or attribute prefix:
class Parent(object):
def __init__(self):
self.__fct()
def __fct(self):
# do some basic stuff
class Child(Parent):
def __init__(self):
super().__init__()
self.__fct()
def __fct(self):
# add other stuff
Using the __ prefix makes Python change the name of this method, both in declaration and where it is used when the class is created (at the time the class statement with its block is itself executed) - and both methods work as if they were named differently, each one only accessible, in an ordinary way, from code in its own class.
Some documentation, mainly older docs, will sometimes refer to this as the mechanism in Python to create "private methods". It is not the samething, although it can serve the same purpose in some use cases (like this). The __fct method above will be renamed respectively to Parent._Parent__fct and Child._Child__fct when the code is executed.
second way, without name mangling:
Without resorting to this name mangling mechanism, it is possible to retrieve attributes from the class where a piece of code is declared by using the __class__ special name (not self.__class__, just __class__) - it is part of the same mechanism Python uses to make argumentless super() work:
class Parent(object):
def __init__(self):
__class__.fct(self) # <- retrieved from the current class (Parent)
def fct(self):
# do some basic stuff
class Child(Parent):
def __init__(self):
super().__init__()
__class__.fct(self)
def fct(self):
# add other stuff
This will also work - just note that as the methods are retrieved from the class object, not from an instance, the instance have to be explicitly passed as an argument when calling the methods.
The name __class__ is inserted automatically in any methods that use it, and will always refer to the class that has the body were it appears - the class itself will be created "in the future", when all the class body is processed and the class command itself is resolved.

Pass the name of the class to a function, assign to a class attribute, outside of a method

Python 3.7:
I have a class definition, where a class attribute is assigned a value based on the class name, and the value is used in a decorator within the class.
I'm looking for a pronoun for "the class currently being defined".
Here's an example:
class MyClass:
# NameError: name '__class__' is not defined
class_logger = find_logger(__class__.__name__)
# __init__ is not important
def __init__(self):
# This works!
self.logger = find_logger(__class__.__name__)
#mydecorator(class_logger)
# mymethod is not important
def mymethod(self):
return 1
What is a suitable pronoun for "the class currently being defined"?
(This is similar to How to get the current Python class name in __init__ regardless of the class of "self"?, but there, the question was "in the definition of init", and at the time was for 2.7. Python 3.x solved that problem.)
It isn't guaranteed that the class object exists and is accessible to the user when the class definition hasn't finished evaluating. Even if it was accessible, it might not be initialized to the extent that you could do anything useful with it.
That said, you may be able to get the name of the class. __qualname__ is an attribute that holds the qualified name of the class / function / method / descriptor / generator instance. You should be able to access it from within the class' definition.
class Fred:
print("Fred's qualname:", __qualname__)
class Barney:
print("Barney's qualname:", __qualname__)
Result:
Fred's qualname: Fred
Barney's qualname: Fred.Barney
If your class isn't defined at the file-level, you might need to do some string manipulation to separate its name from the rest of the path. For example, change the above example to print("Barney's qualname:", __qualname__.rpartition(".")[-1]) to get just "Barney" rather than "Fred.Barney".
Despite my best efforts, I couldn't find documentation that explicitly confirms that __qualname__ has a sensible value when accessed as a regular name and not as an attribute. I'm not fully convinced that this is well-defined behavior, so I don't think I can unreservedly endorse it for production-quality code.
To work with class name during its definition you can also use a metaclass with __prepare__ method:
def find_logger(name):
return name + '_logger'
class PrepareClassLogger(type):
def __prepare__(name, bases, **kwargs):
return {'class_logger': find_logger(name)}
class MyClass(metaclass=PrepareClassLogger):
pass
print(MyClass.class_logger) # MyClass_logger

Using class variables from superclass to initialize class variables in subclass without super()?

I want to use a class variable in my parent class for initializing a class variable in a child class. I think I have found a solution that uses super():
class Parent:
PARENT_CLASS_VAR = 'ABC'
class Child(Parent):
CHILD_CLASS_VAR = super().PARENT_CLASS_VAR
However, I'm curious whether this is a good way to do this and whether there are other ways.
EDIT: Meanwhile, I've also thought that another valid solution is using the __init__ constructor and calling the superclass class variable using self.

Passing an object as a parameter into a sub-class in python

I've been trying to comprehend python's implementation of OOP.
Essentially I need something which is a superclass that defines some global attributes that al l other classes use as input for their methods. Eg:
This is how i thought it should be done:
class One():
def __init__(self, name):
self.name = name
class Two(One):
def __init__(self, name): # name from class one...
One.__init__(self, name)
def method_using_name_from_one(self, name_from_one):
return name_from_one
I guess that I could do this by just declaring all the methods in class Two as in methods of class one, but I'd much prefer to have them separated. So to recap: I want the parameters for the method in class two to use the attributes declared in class One. So essentially I want to pass in an instantiated object as the parameter arguments for class Two methods.
When you say
class Two(One):
One isn't a parameter of class Two. That means class Two inherits from class One. In other words, unless you override a method, it gets everything class One has. edit: When I say this, I mean parameters and functions, I don't mean an instance of the class. Since you have:
def __init__(self, name): # name from class one...
One.__init__(self, name)
self.name is in class Two. In other words, you could just say...
def method_using_name_from_one(self):
return self.name
One thing I would suggest is changing your class One declaration to:
class One(object):
This means it inherits from object, it doesn't mean it's getting passed an object :)
Is this what you meant? Maybe I didn't understand correctly.
If you want the name parameter from One, you could say
def method_using_name_from_one(self, oneInstance):
return oneInstance.name

Passing parameter to base class constructor or using instance variable?

All classes derived from a certain base class have to define an attribute called "path". In the sense of duck typing I could rely upon definition in the subclasses:
class Base:
pass # no "path" variable here
def Sub(Base):
def __init__(self):
self.path = "something/"
Another possiblity would be to use the base class constructor:
class Base:
def __init__(self, path):
self.path = path
def Sub(Base):
def __init__(self):
super().__init__("something/")
I use Python 3.1.
What would you prefer and why? Is there a better way?
In Python 3.0+:
I would go with a parameter to the base class's constructor like you have in the second example. As this forces classes which derive from Base to provide the necessary path property, which documents the fact that the class has such a property and that derived classes are required to provide it. Without it, you would be relying on this being stated (and read) somewhere in your class's docstrings, although it certainly does help to also state in the docstring what the particular property means.
In Python 2.6+:
I would use neither of the above; instead I would use:
class Base(object):
def __init__(self,path):
self.path=path;
class Sub(Base):
def __init__(self):
Base.__init__(self,"something/")
In other words, I would require such a parameter in the base class's constructor, because it documents the fact that all such types will have/use/need that particular parameter and that the parameter needs to be provieded. However, I would not use super() as super is somewhat fragile and dangerous in Python, and I would also make Base a new-style class by inheriting from object (or from some other new-style) class.

Categories

Resources