【问题标题】:Compute len(str(x)) and len(repr(x)) efficiently高效计算 len(str(x)) 和 len(repr(x))
【发布时间】:2020-12-15 13:48:00
【问题描述】:

有没有办法计算len(str(x)) 和/或len(repr(x)) 的结果 先计算str(x)repr(x)?怎么样?

我可能希望根据其打印长度有条件地打印一个对象,所以如果我不打算打印它,我不需要str(x)repr(x)

# How might we redefine lenstr so that str(x) need not be computed?
def lenstr(x):
    return len(str(x))

def maybe_str(x, maxlen=80, subst='*'):
    return subst * maxlen if lenstr(x) > maxlen else str(x)

maybe_str(tuple(range(9)))
# '(0, 1, 2, 3, 4, 5, 6, 7, 8)'
maybe_str(tuple(range(99)))
# '********************************************************************************'

maybe_str(tuple(map(lambda k: tuple(range(k)), range(4))))
# '((), (0,), (0, 1), (0, 1, 2))'
maybe_str(tuple(map(lambda k: tuple(range(k)), range(42))))
'********************************************************************************'

【问题讨论】:

  • 如果你定义了一个有“长度”的对象/类,不管那个长度是多少。每次您想知道它是什么时都不必计算该对象的长度,而是在对象/类中存储一个变量,该变量会随着您在其生命周期和使用期间增加其长度属性而更新。然后,您可以在条件语句中引用此变量。
  • @Bdyce 该解决方案将要求每个对象都有这样的方法,并且不适用于内置对象,例如tuple
  • 一般来说没有什么好的方法可以做到这一点,事实上,即使内置对象具有明确定义的长度,它们所引用的对象的长度也必须递归查询,所以可以你缩小了一些范围?

标签: python python-3.x string printing string-length


【解决方案1】:

一般?不。对于__str____repr__ 的特定已知实现,您可以保留一些有关长度的信息,而无需实际计算字符串。最简单的情况是,如果您知道__str__ = lambda: "",那么您也知道len(str(x))0,而无需“计算”它。

如果您试图避免昂贵的计算并且 __str____repr__ 被重复调用,您可以设置一个记忆函数,这样实际的实现被一个调用一次实现的函数替换,存储该值,然后为所有后续调用返回该存储值。

您还可以使用maxlen 之类的参数创建一个实现__str____repr__ 逻辑的函数,如果最终输出的缓冲区超过该长度,则中止计算。然后将对象上的真正魔术函数定义为调用自定义中止函数,并使用“不中止”的值。在只希望输出特定长度的地方,直接使用自定义函数提前退出。

可以对所有对象执行此操作,但不可取。就像您可以替换内置函数一样,其他代码也可以。违反内置函数的约定是产生微妙且难以追踪的错误的绝佳方式。省去你自己的麻烦,不要这样做。

【讨论】:

  • RE “一般来说?不。”:Python 必须(我假设)在底层对最终的 str 进行部分计算。为了为tuple 创建str,它必须遍历元组的元素,计算元素的str,对吗?你是说 Python 程序员的界面中没有中级魔法?
  • RE "memoized":在我的直接应用程序中,我有一堆对象可能会被打印出很多次,所以一个能记住相应 strs 的堆栈是个不错的主意。
  • str() 的 Python 实现在任何给定对象上调用“魔术方法”__str__()。魔术方法的实际实现会因代码的作者而异。有些会做一些事情,比如分配一个缓冲区并把它填满,而许多实现会直接结合字符串格式和连接操作。具体针对tuple,默认实现在C:github.com/python/cpython/blob/master/Objects/…
【解决方案2】:

您正在谈论更改本机 python 对象的功能。有ways you can do this,但高度警告不要这样做。如果您的想法围绕着简单地节省一些计算成本来获取对象的“长度”属性,我会使用您自己的自定义包装类并使用这些类而不是本机 python 对象来查看extending these objects。您可以在这些类中实现在使用期间跟踪长度的逻辑,从而不必每次都计算长度。

这就是 python 和大多数其他面向对象编程语言的使用方式。通过定义您自己的 data structures 来获得创意,以便通过使用 inheritance 来控制您描述的计算

【讨论】:

  • RE:“你说的是改变原生 python 对象的功能”:不是我。反正不是故意的。对于我的工作,我更喜欢功能性风格,偶尔会为非常特殊的情况开设课程。我宁愿定义一个 lenstr 函数来处理任何对象(或者至少是所有内置函数,如果可能的话),而不是为每个对象定义 lenstr 方法。
  • RE:“发挥创意”:我的意思是类似于@wmorrel 的记忆建议,它适用于我想到的特殊情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多