从字符串创建 Python 对象

发布于 2024-10-21 12:39:51 字数 787 浏览 5 评论 0原文

一些 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 McGuire 建议的静态 parse 方法可能是一个很好的解决方法。

Some Python classes like float can parse strings to create objects:

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

What is that technically? A constructor call with a string? But what if the constructor would also take other parameters for usual object construction (not from strings)?

How to implement a class that can parse strings to create instances?

Addition:

It looks like float(str) is calling the __float__ special method of the passed string - the string knows its float value.

Every object implementing __float__ can be passed to float(obj):

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

This approach works only with conversions to specific types like float and int, since the conversion actually happens in the passed object. What I want is the opposite where the conversion happens in the object which gets the string passed. I think a static parse method, as suggested by Paul McGuire, could be a good work around.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

捂风挽笑 2024-10-28 12:39:51

这是一个带有字符串的构造函数调用。如果您的构造函数需要的不仅仅是字符串值,那么您可以定义一个类方法工厂方法,该方法接受一个字符串,从中提取附加数据(无论您如何对其进行编码),然后使用所有必要的参数调用构造函数。 @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")

It is a constructor call with a string. If you have a constructor that needs more than the string value, then you could define a classmethod factory method that takes a string, extracts the additional data from it (however you have encoded it), and then calls the constructor with all the necessary args. @tiagoboldt referenced this class definition:

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

I would add this method to accept a string of the form "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")
一瞬间的火花 2024-10-28 12:39:51

这只是根据参数类型以不同方式处理参数的一般情况。通常,除非绝对必要,否则测试类型被认为是不好的形式,但 Python 拥有 type()isinstance() 是有原因的!

您会注意到,dict() 构造函数可以采用现有的字典对象、键/值对元组的列表(或其他可迭代对象)或关键字参数(作为字典到达构造函数) ,但作为与选项 1) 不同的参数。在 Java 或其他静态类型语言中,这些都是不同的构造函数方法。但在 Python 中,任何类型都可以在任何参数中传递。只有一个构造函数(或初始值设定项)。

因此,dict 类型必须在其 __init__() 方法中具有一些智能,以将字典或列表作为第一个参数以及可选的关键字参数进行处理。两者都必须是可选的。它的实现方式看起来像这样:(

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 实现的,但希望您能明白这个想法。)

在您自己的对象中,您可以将某些参数设置为可选,并根据需要测试参数的类型,以便根据传入的内容以不同的方式处理它们。如果您想如果能够处理字符串,您可以在 Python 2.x 中使用 isinstance(arg, basestring) (以便测试同时匹配常规字符串和 Unicode 字符串)或仅使用 isinstance(arg, str) Python 3 中的 code>。

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

This is just a general case of handling arguments differently based on their types. Usually it is considered bad form to test types unless it's absolutely necessary, but Python has type() and isinstance() for a reason!

You will notice that the dict() constructor can take an existing dictionary object, a list (or other iterable) of tuples of key/value pairs, or keyword arguments (which arrive at the constructor as a dictionary, but as a different argument from option 1). In Java or another statically-typed language, these would all be different constructor methods. But in Python, any type can be passed in any argument. There is only one constructor (or initializer).

So the dict type has to have some smarts in its __init__() method to handle either a dict or a list as the first argument, and also an optional keyword argument. Both must be optional. The way it's implemented would look something like this:

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)

(Defining a class using objects of its own type is problematic, so I'm sure what I've written wouldn't actually run, and besides dict is actually implemented in C, but you hopefully get the idea.)

In your own objects, then, you can make certain arguments optional, and test the types of arguments as necessary to handle them differently depending on what's passed in. If you want to be able to handle strings, you can use isinstance(arg, basestring) in Python 2.x (so the test matches both regular and Unicode strings) or just isinstance(arg, str) in Python 3.

Factory class methods as suggested by Paul are not a bad idea either, especially for classes where initialization can be performed in a large number of ways. I would name such methods from_str() or so on.

回心转意 2024-10-28 12:39:51
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
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

and in usage:

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
穿越时光隧道 2024-10-28 12:39:51

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

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

What you're doing is a cast. The best way to implement a constructor from a string is to use the init method and pass the string to it.

A more complex example (more than just one string): http://www.java2s.com/Code/Python/Class/Averysimpleclasswithaconstructor.htm

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文