【问题标题】:Override python built-in float() behavior覆盖 python 内置的 float() 行为
【发布时间】:2022-01-18 21:08:42
【问题描述】:

旧标题:将不带“e”的科学计数法字符串转换为 Python 中的浮点数

我使用的程序允许某些...奇怪的格式。实数的一种格式是不带字母字符“E”的科学记数法。例如,“-1.67E-6”可以写成“-1.67-6”。显然, float() 不喜欢这样。我正在编写许多需要在多个字段中进行相同检查的类,因此我需要一个函数来干净地执行此操作。有没有办法覆盖 float() 的内置定义,以便它可以处理这种格式?我认为这将是理想的,但我不确定是否可能。

我目前的解决方法是使用我自己的字符串到浮点函数,如下所示。

str2float(s):
    if re.search(r'([-+][0-9]*.[0-9]*)([-+][0-9]*)', s):
        base, exp = re.findall(r'([-+][0-9]*.[0-9]*)([-+][0-9]*)', X1)[0]
        s = f'{base}E{exp}'
    return float(s)

【问题讨论】:

  • 你的示例输入和示例输出是什么?
  • 我想打电话给float('-1.67-6')并得到-1.67e-06的输出
  • e 之后总是有- 吗?我的意思是,没有你想要1.676 -> 1.67e06的情况吗?
  • 是的,你怎么知道它是正面的还是负面的?
  • re.sub(r'(?<=\d)-(?=\d)', 'E-', '-1.67-6')re.sub(r'(?<=\d)\+(?=\d)', 'E', '-1.67+6') 这样的东西可以工作吗?

标签: python string floating-point exponent


【解决方案1】:

这样的事情怎么样?

def str2float(s):
    sign = '+' if '+' in s else '-'
    l = s.split(sign)
    if (len(l) == 3) and (l[0] == ''):
        return float(sign + l[1] + "E" + sign + l[2])
    elif (len(l) == 2) and (l[0] != ''):
        return float(l[0] + "E" + sign + l[1])
    else:
        return float(s)
    
str2float("-1.67+6") # -1670000.0
str2float("-1.67-6") # 1.67e-06
str2float("1.67+6")  # 1670000.0
str2float("1.67")    # 1.67
str2float("-1.67")   # -1.67

【讨论】:

  • 我之前写过一个类似的函数。我很好奇的是是否可以覆盖内置的float() 函数/类以处理我独特的格式。除了知道这是否可能之外,我还很好奇这方面的最佳实践是什么。我将编辑我的问题以反映我不是在寻求正则表达式的帮助或编写新函数,因为我已经为此准备了一些东西。
【解决方案2】:

您可以利用re.sub 的方式来解释当前有效的科学记数法。

import re

def str_to_float(s: str) -> float:
    s = re.sub(r'(?<=\d)-(?=\d)', 'E-', s)
    s = re.sub(r'(?<=\d)\+(?=\d)', 'E', s)
    return float(s)

print(str_to_float('-1.67E-6')) # -1.67e-06
print(str_to_float('-1.67-6')) # -1.67e-06
print(str_to_float('1.67+6')) # 1670000.0
print(str_to_float('1.67E6')) # 1670000.0
print(str_to_float('-1.67')) # -1.67
print(str_to_float('1.67')) # 1.67

(?&lt;=\d) - 单个数字(0 到 9)的正向回溯。

-\+ - 从字面上匹配字符 -+

(?=\d) - 单个数字(0 到 9)的正向前瞻。

这会定位无效的科学记数法(如float 所见)并用有效的科学记数法替换它们。

【讨论】:

  • 我之前写过一个类似的函数。我很好奇的是是否可以覆盖内置的float() 函数/类以处理我独特的格式。除了知道这是否可能之外,我还很好奇这方面的最佳实践是什么。我将编辑我的问题以反映我不是在寻求正则表达式的帮助或编写新函数,因为我已经为此准备了一些东西。
  • 可以使用您自己的实现来隐藏内置的float,但是,如果您在其他人将使用您的代码的环境中工作,我强烈建议您不要这样做。
【解决方案3】:

我想我找到了我要找的东西。

class float(float):
    def __new__(cls, s):
        if re.search(r'([-+]?[0-9]*.[0-9]*)([-+][0-9]*)', s):
            base, exp = re.findall(r'([-+]?[0-9]*.[0-9]*)([-+][0-9]*)', s)[0]
            s = f'{base}E{exp}'
        return super(float, cls).__new__(cls, s)

这似乎允许我以我想要的方式覆盖float() 的基本行为。这是一个好主意吗?馊主意?为什么?

【讨论】:

  • 1.每当有人看到float 时,他们都会期待某种类型的行为,无论是预期的错误还是type 以意想不到的方式检查(type(float('1.67')) is __builtins__.float)。 2. 这增加了创建float 的额外开销,如果做得足够多,将显着降低性能。 3. 有些情况你几乎肯定没有考虑到这个实现。内置的float 具有经过数百万人测试的好处。几乎所有边缘情况都已被发现。例如,您的中断与 float(2) 这样简单的东西。
  • @Axe,这是我希望得到的响应和反馈类型。我暗自怀疑这不符合最佳实践,但想知道这背后的原因是什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 2016-05-27
  • 2021-05-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多