python是否具有Java Class.forName()的等价物?

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

我需要一个字符串参数,并在python中创建一个在该字符串中命名的类的对象。在爪哇,我会使用Class.forName().newInstance()。在python中是否有等价物?

感谢您的回复。要回答那些想知道我在做什么的人:我想使用命令行参数作为类名,并实例化它。我实际上是在Jython编程和实例化Java类,因此问题的Java性。江户十一〔一〕行得很好。非常感谢。


在Python中的反射比Java更容易和更灵活。

我建议阅读本教程

没有直接函数(我知道)接受完全限定的类名并返回类,但是您拥有构建它所需的所有部分,并且可以将它们连接在一起。

不过有一点建议:当你在Python中时,不要尝试用Java风格编程。

如果你能解释一下你想做什么,也许我们可以帮助你找到一种更为Python式的方法。

这里有一个函数可以满足您的需要:

1
2
3
4
5
6
7
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

您可以将此函数的返回值用作类本身。

下面是一个使用示例:

1
2
3
4
5
6
7
8
9
>>> 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)
>>>

这是怎么回事?

我们正在使用__import__导入保存类的模块,这要求我们首先从完全限定名中提取模块名。然后我们导入模块:

1
m = __import__( module )

在这种情况下,m只指顶层模块,

例如,如果您的类位于foo.baz模块中,那么m将是foo模块。使用getattr( m, 'baz' )可以很容易地获得foo.baz的参考。

为了从顶层模块到类,必须递归地在类名的各个部分使用gettatr

例如,如果您的类名是foo.baz.bar.Model,那么我们将执行以下操作:

1
2
3
4
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

这就是在这个循环中发生的事情:

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

在循环结束时,m将是对类的引用。这意味着m实际上是它的类,例如:

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


假设类在您的范围内:

1
globals()['classname'](args, to, constructor)

否则:

1
getattr(someModule, 'classname')(args, to, constructor)

编辑:注意,你不能给getattr起"foo.bar"这样的名字。你得把它分开。并对每一块从左到右调用getattr()。这将处理以下问题:

1
2
3
module, rest = 'foo.bar.baz'.split('.', 1)
fooBar = reduce(lambda a, b: getattr(a, b), rest.split('.'), globals()[module])
someVar = fooBar(args, to, constructor)


1
2
3
4
5
6
def import_class_from_string(path):
    from importlib import import_module
    module_path, _, class_name = path.rpartition('.')
    mod = import_module(module_path)
    klass = getattr(mod, class_name)
    return klass

号用法

1
2
3
4
5
6
7
In [59]: raise import_class_from_string('google.appengine.runtime.apiproxy_errors.DeadlineExceededError')()
---------------------------------------------------------------------------
DeadlineExceededError                     Traceback (most recent call last)
<ipython-input-59-b4e59d809b2f> in <module>()
----> 1 raise import_class_from_string('google.appengine.runtime.apiproxy_errors.DeadlineExceededError')()

DeadlineExceededError:


还有一个实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def import_class(class_string):
   """Returns class object specified by a string.

    Args:
        class_string: The string representing a class.

    Raises:
        ValueError if module part of the class is not specified.
   "
""
    module_name, _, class_name = class_string.rpartition('.')
    if module_name == '':
        raise ValueError('Class name must contain module part.')
    return getattr(
        __import__(module_name, globals(), locals(), [class_name], -1),
        class_name)


似乎你是从中间开始而不是从开始。你到底想做什么?查找与给定字符串关联的类是达到目的的一种方法。

如果你澄清你的问题,这可能需要你自己的精神重构,一个更好的解决方案可能会出现。

例如:您是否试图根据保存的对象的类型名和一组参数加载该对象?python会拼写这个unpickling,您应该查看pickle模块。而且,即使解压过程完全按照您的描述进行,您也不必担心它在内部如何工作:

1
2
3
4
5
6
7
8
9
10
11
12
>>> class A(object):
...   def __init__(self, v):
...     self.v = v
...   def __reduce__(self):
...     return (self.__class__, (self.v,))
>>> a = A("example")
>>> import pickle
>>> b = pickle.loads(pickle.dumps(a))
>>> a.v, b.v
('example', 'example')
>>> a is b
False


这可以在python标准库中找到,作为unittest.testloader.loadtestsfromname。不幸的是,该方法继续执行其他与测试相关的活动,但第一个HA看起来是可重用的。我已编辑它以删除与测试相关的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def get_object(name):
   """Retrieve a python object, given its dotted.name."""
    parts = name.split('.')
    parts_copy = parts[:]
    while parts_copy:
        try:
            module = __import__('.'.join(parts_copy))
            break
        except ImportError:
            del parts_copy[-1]
            if not parts_copy: raise
    parts = parts[1:]

    obj = module
    for part in parts:
        parent, obj = obj, getattr(obj, part)

    return obj