Создание объектов Python из строк - PullRequest
2 голосов
/ 09 марта 2011

Некоторые классы Python, такие как float, могут анализировать строки для создания объектов:

number_string = "4.5"
assert float(number_string) == 4.5

Что это технически?Вызов конструктора со строкой?Но что, если конструктор также будет принимать другие параметры для обычного построения объекта (не из строк)?

Как реализовать класс, который может анализировать строки для создания экземпляров?

Добавление:

Похоже, float(str) вызывает __float__ специальный метод переданной строки - строка знает свое float значение.

Каждый объект, реализующий __float__, может быть передан в float(obj):

>>> class MyClass:
...     def __float__(self):
...             return 0.01
...
>>> m = MyClass()
>>> float(m)
0.01

Этот подход работает толькос преобразованиями в конкретные типы, такие как float и int, поскольку преобразование фактически происходит в переданном объекте.То, что я хочу, это наоборот, где преобразование происходит в объекте, который получает переданную строку.Я думаю, что статический метод parse, предложенный Полом Макгуайром, может быть хорошим решением.

Ответы [ 4 ]

3 голосов
/ 09 марта 2011

Это вызов конструктора со строкой.Если у вас есть конструктор, которому нужно больше, чем строковое значение, вы можете определить метод фабрики classmethod, который принимает строку, извлекает из нее дополнительные данные (как вы ее кодировали), а затем вызывает конструктор со всеми необходимыми аргументами.,@tiagoboldt ссылался на это определение класса:

class Student(object):
    def __init__ (self, name, age, gender):
        self.name   = name
        self.age    = age
        self.gender = gender

Я бы добавил этот метод для принятия строки вида "имя / возраст / пол":

    @classmethod
    def parse(cls, s):
        # some input validation here would be a good idea
        name,age,gender = s.split('/')
        age = int(age)
        return cls(name, age, gender)

s1 = Student("Bob", 10, "M")
s2 = Student.parse("Bill/12/M")
2 голосов
/ 09 марта 2011

Это просто общий случай обработки аргументов по-разному в зависимости от их типов.Обычно это считается плохой формой для тестирования типов, если это не является абсолютно необходимым, но Python имеет type() и isinstance() по причине!

Вы заметите, что конструктор dict() может принимать существующий объект словаря,список (или другой итерируемый) наборов пар ключ / значение или аргументов ключевых слов (которые поступают в конструктор как словарь, но как аргумент, отличный от варианта 1).В Java или другом статически типизированном языке все они будут разными методами конструктора.Но в Python любой тип может быть передан в любом аргументе.Существует только один конструктор (или инициализатор).

Таким образом, тип dict должен иметь несколько смартов в своем методе __init__(), чтобы обрабатывать в качестве первого аргумента либо dict, либо список, а также необязательныйКлючевой аргумент.Оба должны быть необязательными.То, как это реализовано, будет выглядеть примерно так:

class dict(object):
    def __init__(self, d={}, **kwd):
        if isinstance(d, type(self)):
            self.update(d)
        else:
            for i in d:
                self[i[0]] = i[1]
        self.update(kwd)

(Определение класса с использованием объектов его собственного типа проблематично, поэтому я уверен, что написанное мной на самом деле не будет работать, и, кроме того,dict на самом деле реализован в C, но, надеюсь, вы поняли идею.)

В ваших собственных объектах вы можете сделать некоторые аргументы необязательными и при необходимости протестировать типы аргументов для их различной обработки в зависимостина то, что передается. Если вы хотите иметь возможность обрабатывать строки, вы можете использовать isinstance(arg, basestring) в Python 2.x (чтобы тест соответствовал как обычным, так и Unicode-строкам) или просто isinstance(arg, str) в Python 3.

Методы фабричного класса, предложенные Полом, тоже неплохая идея, особенно для классов, в которых инициализация может выполняться множеством способов.Я бы назвал такие методы from_str() или около того.

1 голос
/ 09 марта 2011
class MyObject(object):
    def __init__(self, data):
        super(MyObject,self).__init__()
        if isinstance(data, self.__class__):  # copy constructor
            self.value = data.value
        elif isinstance(data, basestring):
            self.value = float(data)          # parse string
        else:
            self.value = data

и используется:

a = MyObject(3.9)         # a.value = 3.9
b = MyObject("3.9")       # string constructor - b.value = 3.9
c = MyObject(a)           # copy constructor - c.value = 3.9
0 голосов
/ 09 марта 2011

То, что вы делаете, это актерский состав.Лучший способ реализовать конструктор из строки - это использовать метод init и передать ему строку.

Более сложный пример (более одной строки): http://www.java2s.com/Code/Python/Class/Averysimpleclasswithaconstructor.htm

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