Class.forName().newInstance()
。Python中是否有相当的方法?
感谢回复。为了回答那些想知道我在做什么的人:我希望将命令行参数用作类名,并实例化它。我实际上是在编写Jython并实例化Java类,因此问题具有Java特性。
getattr()
非常好用。非常感谢。Class.forName().newInstance()
。Python中是否有相当的方法?
getattr()
非常好用。非常感谢。在Python中,反射比Java要容易得多并且更加灵活。
我建议阅读这个教程(在archive.org上)
没有直接的函数(据我所知)可以接受完全限定的类名并返回类,但是您有所有构建它所需的零件,并且您可以将它们连接在一起。
但是有一个建议:当您使用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
模块。
我们可以使用getattr( m, 'baz' )
轻松地获取到foo.baz
的引用。
要从顶级模块获取类,必须在类名称的各个部分上递归使用getattr
。
例如,假设你的类名为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
__import__
的存在意义。像 Django 这样进行模块加载魔法的项目经常使用它。不错的回答。 - cdlearyget_class = lambda name: reduce(getattr, name.split('.')[1:], __import__(name.partition('.')[0]))
可以翻译为“获取类 = lambda 名称: reduce(getattr, 名称.split('.')[1:], import(名称.partition('.')[0]))”,虽然 'object.from_name' 可能更好。例如:get_class('decimal.Decimal')、get_class(模块名称)。 - jfs假设这个类在你的作用域中:
globals()['classname'](args, to, constructor)
否则:
getattr(someModule, 'classname')(args, to, constructor)
编辑:注意,您不能像“ foo.bar”这样为getattr指定名称。 您需要通过.拆分它,并从左到右在每个片段上调用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)
attrs = 'foo.bar.baz'.split('.'); fooBar = reduce(getattr, attrs[1:], __import__(attrs[0]))
- jfsmodule,_,attrs = 'foo.bar.baz'.partition('.'); fooBar = reduce(getattr,attrs,__import__(module))
- jfsdef 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
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:
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)
if module_name
的 LBYL 很冗余,因为如果你只是删除这些行,你会得到的错误是:ValueError: Empty module name
。 - bukzor看起来你是从中间开始而不是从头开始。你真正想做什么?找到与给定字符串相关联的类只是达到目的的手段。
如果你能澄清问题,可能需要进行自我思维重构,更好的解决方案可能会呈现出来。
例如:你是否试图根据类型名称和一组参数加载保存的对象?Python将其称为反序列化,你应该查看pickle模块。即使反序列化过程恰好符合您描述的内容,您也不必担心其内部工作方式:
>>> 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。不幸的是,该方法继续执行其他与测试相关的活动,但是第一个部分看起来是可重用的。我已经编辑过它,以删除与测试相关的功能:
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
我需要获取 my_package
中所有现有类的对象。因此,我将所有必要的类导入到 my_package
的 __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)]
在module_name = 'my_package'
处
检查文档:https://docs.python.org/3/library/inspect.html#inspect.getmembers
importlib.import
的例子,这个函数已经从 Python 3 回溯到了 2.7 版本(https://docs.python.org/2/library/importlib.html)。 - Pat