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

时间:2009-01-17 08:10:49

标签: java python class instantiation

我需要获取一个字符串参数,并在Python中创建该字符串中指定的类的对象。在Java中,我会使用Class.forName().newInstance()。 Python中是否有等价物?


感谢您的回复。要回答那些想知道我在做什么的人:我想使用命令行参数作为类名,并实例化它。我实际上是在Jython中编程并实例化Java类,因此问题的Java-ness。 getattr()效果很好。非常感谢。

7 个答案:

答案 0 :(得分:153)

python中的反射比Java更容易,更灵活。

我建议您阅读此tutorial

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

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

如果你能解释一下你正在尝试做什么,也许我们可以帮助你找到一种更加pythonic的方式。

这是一个可以满足您需求的功能:

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

您可以使用此函数的返回值,就好像它是类本身一样。

这是一个用法示例:

>>> 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__导入包含该类的模块,这要求我们首先从完全限定名称中提取模块名称。然后我们导入模块:

m = __import__( module )

在这种情况下,m仅会引用顶级模块

例如,如果您的班级位于foo.baz模块中,则m将成为模块foo
我们可以使用foo.baz

轻松获取对getattr( m, 'baz' )的引用

要从顶级模块进入类,必须在类名的部分递归使用gettatr

比如说,如果您的班级名称是foo.baz.bar.Model,那么我们这样做:

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

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

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

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

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

答案 1 :(得分:24)

假设班级在您的范围内:

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

否则:

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

编辑:注意,你不能给getattr这个'foo.bar'这个名字。你需要拆分它。并从左到右对每个部分调用getattr()。这将处理:

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

答案 2 :(得分:11)

G=some_graph()

import matplotlib.pyplot as plt
plt.figure(figsize=(32,32))

# use graphviz to find radial layout
pos=nx.graphviz_layout(G,prog="dot",
                       root=1000,
                       args='-splines=true -nodesep=0.6 -overlap=scalexy'
                       )

nx.draw(G,pos,
        with_labels=True,
        alpha=0.5,
        node_size=600,
        font_size=10
        )

plt.savefig("imagenet_layout.png")

用法

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

答案 3 :(得分:4)

又一个实施。

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)

答案 4 :(得分:3)

似乎你从中间而不是从头开始接近这个。你真的想做什么?查找与给定字符串关联的类是达到目的的手段。

如果您澄清了可能需要自己进行心理重构的问题,可能会出现更好的解决方案。

例如:您是否尝试根据其类型名称和一组参数加载已保存的对象? Python拼写这个unpickling你应该看看pickle module。尽管unpickling流程完全符合您的描述,但您不必担心它在内部如何工作:

>>> 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

答案 5 :(得分:1)

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

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

答案 6 :(得分:0)

我需要获取my_package中所有现有类的对象。因此,我将所有必要的类导入到my_package的{​​{1}}中。

所以我的目录结构是这样的:

__init__.py

我的/my_package - __init__.py - module1.py - module2.py - module3.py 看起来像这样:

__init__.py

然后我创建一个像这样的函数:

from .module1 import ClassA
from .module2 import ClassB

def get_classes_from_module_name(module_name): return [_cls() for _, _cls in inspect.getmembers(__import__(module_name), inspect.isclass)]

检查文档:https://docs.python.org/3/library/inspect.html#inspect.getmembers

相关问题