How to get class path in Python - python

In Python, we can define a class and print it as such:
class a:
num = 1
b = a()
print(b)
And we would get the output:
<class '__main__.a'>
I'm trying to identify unique classes, and I have some classes with longer paths. I would like to extract the "class path", or __main__.a in the case above. For example, if I print some longer class I would get:
<class 'django_seed.tests.Game'>
<class 'django_seed.tests.Player'>
<class 'django_seed.tests.Action'>
And I would like to extract:
'django_seed.tests.Game'
'django_seed.tests.Player'
'django_seed.tests.Action'
Since I can cast <class 'django_seed.tests.Game'> to a string, I can substring it quite easily with '<class 'django_seed.tests.Game'>'[8:-2], but I'm sure there must be a cleaner way. Thanks!

The __module__ attribute can be used to access the "path" of a class (where it was defined) and the __name__ attribute returns the name of the class as a string
print(f'{YourClass.__module__}.{YourClass.__name__}')

You can use inspect:
import inspect
print((inspect.getmodule(a).__file__))

Related

Python strange namespace bahavior for class factory

I tried to write simple class factory using the "type" method.
I called myclass_factory twice and It returned identical namespaces
(case1 and case2). But the values of myclass attribute in that namespaces were different (!).
Actualy it just what I need but I can not undestnad why I got that result.
For my udestanding, since case1 and case2 are not objects but just same namespace (<class 'main.MyClass'>) they should refer to the same memory and should be case1.myclass = case2.myclass
Please explain how It could be so?
>>> def myclass_factory(myclass):
... return type('MyClass',(object,),{'myclass': myclass})
...
>>> class class1:
... pass
...
>>> class class2:
... pass
...
>>> case1 = myclass_factory(class1)
>>> case2 = myclass_factory(class2)
>>>
>>> case1
<class '__main__.MyClass'>
>>> case2
<class '__main__.MyClass'>
>>>
>>> case1.myclass
<class '__main__.class1'>
>>> case2.myclass
<class '__main__.class2'>
>>>
>>>
Actually case 1 and case 2 are objects since you instantiate them. They are type objects and thus ordinary python objects. So you create two different type objects.
also see this answer: Link to answer
Also see This description
This is essentially equivalent to the following "normal" code for defining classes:
def MyClass(object):
myclass = class1
case1 = MyClass
def MyClass(object):
myclass = class2
case2 = MyClass
print(case1.myclass)
print(case2.myclass)
Types/classes are first-class objects, and creating a new type with the same name has no effect on the previous class one with that name that was saved in the variable case1.

python: why does `type(super())` return <class 'super'>?

A short inheritance example:
class Person:
def __init__(self, fname, lname):
self.firstname = fname
self.lastname = lname
class Student(Person):
def __init__(self, fname, lname):
super().__init__(fname, lname)
print(type(super()))
Now entering Student("test", "name") will result in <class 'super'> being printed to the console. I'm not familiar with this format. When I do type(int) I see the type as type, not as <class 'int'>. Can someone explain what is going on here?
If you take a look at the docs,
Return a proxy object that delegates method calls to a parent or sibling class of type.
This proxy object is of type super; assuming super_object = super(), then type(super_object) returns a type object that describes the class to which all super objects belong to. Just like type(0) returns a type object that describes integers. <class 'int'> is how this type object prints itself. Fun fact: you already know this object.
>>> int
<class 'int'>
>>> type(0)
<class 'int'>
>>> type(0) == int
True
Note that in Python, constructor for a class is the type object itself. So when you write int(), you are constructing a new object of type int, just like when you write Student("test", "name"), you are constructing a new object of type Student. And so it is with super as well:
>>> type(super()) == super
True
To round out this answer, I will note something very, very obvious, but possibly worth mentioning here just in case. A variable might, and often does, differ from how its value is displayed. When you say
x = 3
print(x)
you don't expect the answer to be x, but 3, because that is the way the value inside x displays itself (via int.__str__ method). int is just another variable, one that happens to contain the integer type object. This type object displays itself as <class 'int'>, not int. int is just a variable name.
>>> my_shiny_number = int
>>> my_shiny_number()
0
>>> type(my_shiny_number())
<class 'int'>
And conversely (and please never ever do this in real code, this is for illustration purposes only):
>>> int = str
>>> int()
''
>>> type(int())
<class 'str'>

What is the type of the object that instantiates classes in python?

I have a problem that I don't even know how to search for. Look at this simple class as an example:
class Student(object):
def _init_(self):
self.id = 0
def inc(self):
self.id += 1
std_gen = Student
What is the type of std_gen?
I tried:
print(type(std_gen))
and I got this:
<class 'type'>
I need to find it's type and add it to a docstring. I can't even find something that returns True with isinstance(std_gen, something)
Edit: I found isinstance(std_gen, type) returns True but that barely makes sense in a docstring. What does that mean?
Class Student is an instance of type 'type'. See metaclass for more information. So type(Student) is 'type'. So
s = Student()
std_gen = Student
type(s) // <class 'Student'>
type(std_gen) // <class 'type'>
To sum up, s is instance of Student, Student is instance of type and stu_gen is just alias of Student.
I believe this is the solution that you're looking for.
print(type(std_gen()))

Fetching python class name while using abstract classes with `abc` library

I want to extract the python class name while using abstract classes with abc library. I unfortunately instead receive the class name ABCMeta.
import abc
class A(abc.ABC)
pass
class B(A)
pass
print(A.__class__.__name__) # output: 'ABCMeta'
print(B.__class__.__name__) # output: 'ABCMeta'
print(str(A)) # output: "<class '__main__.A'>"
print(str(B)) # output: "<class '__main__.B'>"
I expect that I should receive the output as below
print(A.__class__.__name__) # output: 'A'
print(B.__class__.__name__) # output: 'B'
The str(A) and str(B) seems to print the class name so I assume the class name can be extracted from somewhere. But nonetheless, I am not interested to use str to parse and get the class name.
Recall that a metaclass is the type of a class, while a class is the type of its instances.
If we have a = A(), a is of type A, and A is of type abc.ABCMeta. Therefore, you should naturally expect that A.__class__ and B.__class__ both return abc.ABCMeta, since they are instances of it!
What you want is the names of A and B themselves, which you can get with A.__name__ and B.__name__ respectively.
Use just the __name__ property
print(A.__name__)
#A
A in itself is a class, if you use A.__class__ you are getting it’s metaclass therefore it’s metaclass’ name.

What is the default `__reduce__` in Python?

import pickle
class A:
pass
pickle.dumps(B().__reduce__())
yields
(<function _reconstructor at 0x1010143b0>, (<class '__main__.B'>, <class 'object'>, None))
What is this function "_reconstructor". It's neither B, B.__init__, nor B.__new__ as I expected.
I have to make 2 changes to get that result:
Change the name of your class from A to B.
Remove the outer pickle.dumps() call.
In any case, pickle is free to do anything it likes to reconstruct the object ;-) In this case, you can find the _reconstructor() function in Lib/copyreg.py.

Categories

Resources