Does Python Have an Equivalent to Java Class.Forname()

Does python have an equivalent to Java Class.forName()?

Reflection in python is a lot easier and far more flexible than it is in Java.

I recommend reading this tutorial (on archive.org)

There's no direct function (that I know of) which takes a fully qualified class name and returns the class, however you have all the pieces needed to build that, and you can connect them together.

One bit of advice though: don't try to program in Java style when you're in python.

If you can explain what is it that you're trying to do, maybe we can help you find a more pythonic way of doing it.

Here's a function that does what you want:

def get_class( kls ):
parts = kls.split('.')
module = ".".join(parts[:-1])
m = __import__( module )
for comp in parts[1:]:
m = getattr(m, comp)
return m

You can use the return value of this function as if it were the class itself.

Here's a usage example:

>>> D = get_class("datetime.datetime")
>>> D
<type 'datetime.datetime'>
>>> D.now()
datetime.datetime(2009, 1, 17, 2, 15, 58, 883000)
>>> a = D( 2010, 4, 22 )
>>> a
datetime.datetime(2010, 4, 22, 0, 0)
>>>

How does that work?

We're using __import__ to import the module that holds the class, which required that we first extract the module name from the fully qualified name. Then we import the module:

m = __import__( module )

In this case, m will only refer to the top level module,

For example, if your class lives in foo.baz module, then m will be the module foo

We can easily obtain a reference to foo.baz using getattr( m, 'baz' )

To get from the top level module to the class, have to recursively use gettatr on the parts of the class name

Say for example, if you class name is foo.baz.bar.Model then we do this:

m = __import__( "foo.baz.bar" ) #m is package foo
m = getattr( m, "baz" ) #m is package baz
m = getattr( m, "bar" ) #m is module bar
m = getattr( m, "Model" ) #m is class Model

This is what's happening in this loop:

for comp in parts[1:]:
m = getattr(m, comp)

At the end of the loop, m will be a reference to the class. This means that m is actually the class itslef, you can do for instance:

a = m() #instantiate a new instance of the class    
b = m( arg1, arg2 ) # pass arguments to the constructor


Dynamically instantiate object of the python class similar to PHP new $classname?

Here is some code I use to go from a full class path (e.g. foo.bar.baz.TheClass) to the class itself:

def get_class(class_path):
module_path, class_name = class_path.rsplit(".", 1)

try:
module = __import__(module_path, fromlist=[class_name])
except ImportError:
raise ValueError("Module '%s' could not be imported" % (module_path,))

try:
cls = getattr(module, class_name)
except AttributeError:
raise ValueError("Module '%s' has no class '%s'" % (module_path, class_name,))

return cls

Usage:

>>> get_class('twisted.internet.nonexistant.Deferred')

Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
get_class('twisted.internet.nonexistant.Deferred')
File "<pyshell#1>", line 7, in get_class
raise ValueError("Module '%s' could not be imported" % (module_path,))
ValueError: Module 'twisted.internet.nonexistant' could not be imported
>>> get_class('twisted.internet.defer.NoClass')

Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
get_class('twisted.internet.defer.NoClass')
File "<pyshell#13>", line 12, in get_class
raise ValueError("Module '%s' has no class '%s'" % (module_path, class_name,))
ValueError: Module 'twisted.internet.defer' has no class 'NoClass'
>>> get_class('twisted.internet.defer.Deferred')
<class twisted.internet.defer.Deferred at 0x02B25DE0>

Note that this doesn't necessarily return a class, it just returns the attribute of the imported module:

>>> get_class('twisted.internet')
<module 'twisted.internet' from 'C:\Python26\lib\site-packages\twisted\internet\__init__.pyc'>

Initialise class object by name

If the class is in your scope:

get_class = lambda x: globals()[x]

If you need to get a class from a module, you can use getattr:

import urllib2
handlerClass = getattr(urllib2, 'HTTPHandler')

Distinction between ClassObject.getClass,ClassName.class and Class.forName( ClassName )

Class.forName loads and initializes the class. obj.getClass() returns the class object loaded into permgen. If the class is loaded by the same classloader == has to return true. When you are see false for == comparison it means that they are loaded by different classloaders.

C# equivalent of class.forName() in Java

You mean, like this?

typeof(YourClass).Name

To clarify, in .NET framework there's a class named Type. This class has a property named Name that retrieves the name of the class.

So, to retrieve the Type of a class in compile time you can use typeof.

var typeName = typeof(YourClass).Name

If you doesn't know the type at runtime, you can retrieve it with the GetType() method. This is common for all .NET objects.

Animal a = new Dog();
var typeName = a.GetType().Name;

Answer for Edit 1

You need to pass a Type parameter

void X(Type classType) 
{
var className = classType.Name;
Console.WriteLine(className);
}

And a call to X should be like this

X(typeof(YourClass));

or

X(YourInstance.GetType());

Terrifying initial values - mutable types share same reference?

You have defined a class attribute instead of an instance attribute. Python is doing the right thing.

Instead of

class A(object):
v = [] # Class attribute, shared across all instances!

you need

class A(object):
def __init__(self): # Instance attribute, created anew for each new object
self.v = []

How to dynamically load a Python class

From the python documentation, here's the function you want:

def my_import(name):
components = name.split('.')
mod = __import__(components[0])
for comp in components[1:]:
mod = getattr(mod, comp)
return mod

The reason a simple __import__ won't work is because any import of anything past the first dot in a package string is an attribute of the module you're importing. Thus, something like this won't work:

__import__('foo.bar.baz.qux')

You'd have to call the above function like so:

my_import('foo.bar.baz.qux')

Or in the case of your example:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

EDIT: I was a bit off on this. What you're basically wanting to do is this:

from my_package.my_module import my_class

The above function is only necessary if you have a empty fromlist. Thus, the appropriate call would be like this:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')


Related Topics



Leave a reply



Submit