Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check in python if some class (by string name) exists?

Is it possible to check if some class exists? I have class names in a json config file. I know that I can simply try to create an object by class name string but that is actually a bad idea because the class constructor can do some unexpected stuff while at this point in time I just want to check if my config is valid and all mentioned classes are available.

Is there any way to do it?

EDIT: Also I do understand that u can get all the methods from some module, in my case I am not sure and don't actually care from what module comes the method. It can be from any import statement and I probably don't know where exactly from.

like image 948
Alexandr Avatar asked May 27 '15 12:05

Alexandr


People also ask

Why do classes exist python?

Classes provide a means of bundling data and functionality together. Creating a new class creates a new type of object, allowing new instances of that type to be made. Each class instance can have attributes attached to it for maintaining its state.

What type is class python?

Python is an object oriented programming language. Almost everything in Python is an object, with its properties and methods. A Class is like an object constructor, or a "blueprint" for creating objects.

What is a class in python?

A class is a code template for creating objects. Objects have member variables and have behaviour associated with them. In python a class is created by the keyword class . An object is created using the constructor of the class. This object will then be called the instance of the class.

Is instance of class python?

Every python object is an instance of some class (built-in or otherwise). A class is just an instance of another class (called metaclass when the distinction matters; commonly type but anyone can define a metaclass, IIRC even without inheriting from type ). A traceback is just an instance of traceback .


2 Answers

Using eval() leaves the door open for arbitrary code execution, for security's sake it should be avoided.

Especially if you ask for a solution for such a problem here. Then we can assume that you do not know these risks sufficiently.

import sys

def str_to_class(str):
    return reduce(getattr, str.split("."), sys.modules[__name__])

try:
    cls = str_to_class(<json-fragment-here>)
except AttributeError:
    cls = None

if cls:
    obj = cls(...)
else:
    # fight against this

This avoids using eval and is approved by several SO users. Solution is similar to Convert string to Python class object?.

like image 125
wenzul Avatar answered Sep 20 '22 23:09

wenzul


You can parse the source to get all the class names:

from ast import ClassDef, parse
import importlib
import inspect

mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
names = [kls.name for kls in p.body if isinstance(kls, ClassDef)]

Input:

class Foo(object):
   pass

class Bar(object):
    pass

Output:

['Foo', 'Bar']

Just compare the class names from the config to the names returned.

{set of names in config}.difference(names)

If you want to include imported names you can parse the module it was imported from but depending on how it was imported you can still find cases that won't work:

from ast import ClassDef, parse, ImportFrom
import importlib
import inspect

mod = "test"
mod = importlib.import_module(mod)
p = parse(inspect.getsource(mod))
names = []
for node in p.body:
    if isinstance(node, ClassDef):
        names.append(node.name)
    elif isinstance(node, ImportFrom):
        names.extend(imp.name for imp in node.names)

print(names)

Input:

from test2 import Foobar, Barbar, foo  

class Foo(object):
   pass

class Bar(object):
    pass

test2:

foo = 123

class Foobar(object):
    pass

class Barbar(object):
    pass

Output:

['Foobar', 'Barbar', 'Foo', 'Bar']
like image 27
Padraic Cunningham Avatar answered Sep 20 '22 23:09

Padraic Cunningham