从字符串创建Python对象

时间:2011-03-09 17:35:53

标签: python parsing constructor

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

此方法仅适用于特定类型(如floatint)的转换,因为转换实际上发生在传递的对象中。我想要的是相反的地方,转换发生在传递字符串的对象中。我认为Paul McCGuire建议的静态parse方法可能是一个很好的解决方法。

4 个答案:

答案 0 :(得分:3)

这是一个带字符串的构造函数调用。如果你有一个构造函数需要超过字符串值,那么你可以定义一个classmethod工厂方法,它接受一个字符串,从中提取其他数据(但你已经编码),然后用所有必要的args调用构造函数。 @tiagoboldt引用了这个类定义:

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

我会添加此方法以接受“name / age / 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")

答案 1 :(得分:2)

这只是根据类型处理不同参数的一般情况。通常认为测试类型的形式不好,除非绝对必要,但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实现的,但你希望得到想法。)

在您自己的对象中,您可以使某些参数成为可选参数,并根据传入的内容测试必要的参数类型,以便对它们进行不同的处理。如果您希望能够处理字符串,则可以使用{{ 1}}在Python 2.x中(所以测试匹配常规字符串和Unicode字符串)或者仅仅是Python 3中的isinstance(arg, basestring)

Paul建议的工厂类方法也不是一个坏主意,特别是对于可以以多种方式执行初始化的类。我会将这些方法命名为isinstance(arg, str)等。

答案 2 :(得分:1)

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

答案 3 :(得分:-1)

你正在做的是一个演员。从字符串实现构造函数的最佳方法是使用 init 方法并将字符串传递给它。

一个更复杂的例子(不只是一个字符串):http://www.java2s.com/Code/Python/Class/Averysimpleclasswithaconstructor.htm