Есть ли у python эквивалент класса Java.forName()?


у меня есть необходимость взять строковый аргумент и создать объект класса с именем в этой строке в Python. В Java, я бы использовал Class.forName().newInstance(). Есть ли эквивалент в Python?


Спасибо за ответы. Чтобы ответить тем, кто хочет знать, что я делаю: я хочу использовать аргумент командной строки в качестве имени класса и создать его экземпляр. Я на самом деле программирую в Jython и создаю экземпляры классов Java, следовательно, Java-ness вопроса. getattr() работает отлично. Большое спасибо.

6 82

6 ответов:

отражение в python намного проще и гораздо более гибко, чем в Java.

я рекомендую прочитать это учебник

нет прямой функции (о которой я знаю), которая принимает полное имя класса и возвращает класс, однако у вас есть все части, необходимые для его создания, и вы можете соединить их вместе.

один совет: не пытайтесь программировать в стиле Java, когда вы находитесь питон.

если вы можете объяснить, что это такое, что вы пытаетесь сделать, может быть, мы можем помочь вам найти более подходящие для Python способ сделать это.

вот функция, которая делает то, что вы хотите:

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 на самом деле класс itslef, вы можете сделать, например:

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

предполагая, что класс находится в вашей области:

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

В противном случае:

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

Edit: Примечание, Вы не можете дать имя, как 'foo.бар' с функцией 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)
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

использование

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)

Кажется, вы приближаетесь к этому с середины, а не с начала. Что ты на самом деле пытаешься сделать? Поиск класса, связанного с данной строкой, является средством для достижения цели.

Если вы проясните свою проблему, которая может потребовать вашего собственного ментального рефакторинга, может появиться лучшее решение.

например: вы пытаетесь загрузить сохраненный объект на основе его имени типа и набора параметров? Python заклинания это распиливание, и вы должны посмотреть на модуль рассольник. И хотя процесс распаковки делает именно то, что вы описываете, вам не нужно беспокоиться о том, как он работает внутри:

>>> 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 выглядит многоразовым. Я отредактировал его, чтобы удалить функциональность, связанную с тестом:

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