Python: прочитать строку, а затем создать экземпляр класса с именем в строке - PullRequest
0 голосов
/ 29 июля 2010

Извините, если я не был достаточно ясен в названии, не стесняйтесь исправить это, если вы найдете лучший способ выразить это:

У меня есть файл, в котором есть имена классов, т.е.:

classa
classb
classb
classc
classc
classc

Затем я хочу прочитать его построчно и динамически создать этот класс.Я хотел бы сделать что-то подобное в php:

while (!eof())
{
   $class=fread(..)
   $tab[] = new $class();
}

Как бы вы сделали это в python (если это возможно)?

Большое спасибо!

Редактировать: послечитая ответы, чтобы быть более точным в том, что я планирую делать: я не планирую делать такие простые вещи.Это будет гораздо сложнее: я хочу, чтобы пользователь, который не знает программирования, отредактировал простой текстовый файл, скопировал / вставил некоторые объявления и изменил их свойства, а также повторно запустил своего рода анализатор, который повторно запуститПакетно и показать результат сложных операций. Упрощенный Пример файла:

car:(red,4_wheels,4_places)
bike:(blue,2_wheels,1_place)

Затем пользователь изменит его на:

car:(red,4_wheels,4_places)
car:(yellow,4_wheels,2_places)
bike:(blue,2_wheels,1_place)
bike:(green,2_wheels,2_places)

А затем с помощью Python я прочитаю этот файл, создаюдва экземпляра класса автомобиля и два экземпляра класса велосипеда .Таким образом, пользователь, который не понимает / не знает python, сможет редактировать файл, не касаясь строки кода.Я думаю, что это правильный путь, если у вас есть другие предложения для этого кода, пожалуйста!

Оливье Понс

Ответы [ 6 ]

3 голосов
/ 29 июля 2010

Предполагая, что ваши классы уже находятся в области видимости (то есть они не находятся в отдельном модуле), вы можете очень легко ссылаться на класс по его имени через диктовку globals().Например:

class Foo:
    pass

foo_cls = globals()['Foo']
foo = foo_cls()
# foo is now an instance of __main__.Foo
2 голосов
/ 29 июля 2010

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

classes = {'classa': classa, 'classb': classb}
cls = type(classes[line], (object,), {})  ## or whichever method to instantiate you prefer

Но в целом это не такпо-моему, очень питонская вещь.

1 голос
/ 29 июля 2010

Поскольку вы в любом случае используете YAML, рассмотрите возможность использования PyYAML с сериализованными классами, происходящими из метакласса yaml.YAMLObject, или для регистрации собственного представителя.

Из документации PyYAML:

class Monster(yaml.YAMLObject):
    yaml_tag = u'!Monster'
    def __init__(self, name, hp, ac, attacks):
        self.name = name
        self.hp = hp
        self.ac = ac
        self.attacks = attacks
    def __repr__(self):
        return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
            self.__class__.__name__, self.name, self.hp, self.ac, self.attacks)

print yaml.load("""
--- !Monster
name: Cave spider
hp: [2,6]    # 2d6
ac: 16
attacks: [BITE, HURT]
""")

отпечатков Monster(name='Cave spider', hp=[2, 6], ac=16, attacks=['BITE', 'HURT'])

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

1 голос
/ 29 июля 2010

Предполагая, что все классы объявлены в модуле foo:

classname = sys.stdin.read().rstrip()
cls = getattr(foo, classname)()

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

1 голос
/ 29 июля 2010

Чтение каждой строки из файла довольно просто:

with open(filename) as f:
    for line in f:

Первое, что приходит на ум при создании класса, это функция type:

        cls = type(line, (object,), {})

Это будетсоздайте новый пустой класс, который является подклассом object и имеет имя, указанное в содержимом строки.

Однако мне интересно, почему вы пытаетесь это сделать.Такой пустой класс не очень полезен в Python.

0 голосов
/ 29 июля 2010

Это должно быть довольно легко возможно при использовании словаря классов (не то, чтобы это не обязательно было ограничением, так как к каждому пространству имен python можно обращаться как к словарю, поэтому, если вы хотите, чтобы эти классы сказали, что все находятся внутри модуля или другого класса, просто замените классы атрибутом __dict__ класса или используйте глобальные переменные, как предлагали другие):

classes = dict()
with open('filename') as f:
    for line in f:
        classes[line] = class()

(детали реализации могут отличаться).

Однако вы, возможно, захотите использовать травление вместо этого, так как этот подход кажется некорректным (хотя он может хорошо работать в PHP, хотя :-)).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...