max*_*max 14 python string iterable python-3.x
更新:
2006年在python.org上提出了使内置字符串不可迭代的想法.我的问题不同之处在于我试图偶尔禁止这个功能; 仍然这整个线程非常相关.
以下是Guido的批评意见,他们str在试验基础上实施了不可迭代的评论:
[...]我实现了这个(这很简单)然后发现我必须修复大量遍布字符串的地方.例如:
sre解析器和编译器使用set("0123456789")之类的东西,并迭代输入regexp的字符来解析它.
difflib有两个字符串列表定义的API(文件的典型逐行差异),或两个字符串(典型的行内差异),甚至两个任何列表(对于广义序列差异) .
optparse.py,textwrap.py,string.py中的小变化.
而且我甚至还没有在regrtest.py框架工作的地方(由于difflib问题).
我放弃了这个项目; 补丁是SF补丁1471291.我不再赞成这个想法; 它只是不实用,而且我在sre和difflib中找到的用例都反驳了迭代字符串的好理由的前提.
原始问题:
虽然字符串的一个简洁功能是字符串是可迭代的,但当与鸭子打字相结合时,它可能会导致灾难:
# record has to support [] operation to set/retrieve values
# fields has to be an iterable that contains the fields to be set
def set_fields(record, fields, value):
for f in fields:
record[f] = value
set_fields(weapon1, ('Name', 'ShortName'), 'Dagger')
set_fields(weapon2, ('Name',), 'Katana')
set_fields(weapon3, 'Name', 'Wand') # I was tired and forgot to put parentheses
Run Code Online (Sandbox Code Playgroud)
除了isinstance(fields, str)在无数地方进行测试之外,没有任何例外,也没有任何例外.在某些情况下,这个bug需要很长时间才能找到.
我想在我的项目中完全禁止字符串被视为可迭代的.这是个好主意吗?它可以轻松安全地完成吗?
也许我可以子类化内置,str这样我就需要显式调用,get_iter()如果我希望它的对象被视为可迭代的.然后每当我需要一个字符串文字时,我会创建一个这个类的对象.
以下是一些与切线相关的问题:
遗憾的是,没有任何方法可以自动执行此操作.你提出的解决方案(一个str不可迭代的子类)遇到了同样的问题isinstance()......即,你必须记住在使用字符串的任何地方都使用它,因为没有办法让Python使用它代替本地课程.当然,你无法对内置对象进行修补.
我可能会建议,如果你发现自己编写了一个带有可迭代容器或字符串的函数,那么你的设计可能有问题.但有时你无法避免它.
在我看来,最不干扰的事情就是将检查放入一个函数中,并在进入循环时调用它.这至少会将行为改变到你最有可能看到它的地方:在for声明中,不要埋没在某个类的某个地方.
def iterate_no_strings(item):
if issubclass(item, str): # issubclass(item, basestring) for Py 2.x
return iter([item])
else:
return iter(item)
for thing in iterate_no_strings(things):
# do something...
Run Code Online (Sandbox Code Playgroud)
扩展,并从中得出答案:
不,你不应该这样做.
你可以做到,你给出的方法可能是最好的方法(对于记录,我认为子分类是更好的选择如果你必须这样做,请参阅@ kindall的方法)但它根本不值得做,并且它不是非常pythonic.首先避免错误.在您的示例中,您可能想问自己这是否是一个问题清晰的问题,以及命名参数或splat是否是更好的解决方案.
例如:更改订单.
def set_fields(record, value, *fields):
for f in fields:
record[f] = value
set_fields(weapon1, 'Dagger', *('Name', 'ShortName')) #If you had a tuple you wanted to use.
set_fields(weapon2, 'Katana', 'Name')
set_fields(weapon3, 'Wand', 'Name')
Run Code Online (Sandbox Code Playgroud)
例如:命名参数.
def set_fields(record, fields, value):
for f in fields:
record[f] = value
set_fields(record=weapon1, fields=('Name', 'ShortName'), value='Dagger')
set_fields(record=weapon2, fields=('Name'), value='Katana')
set_fields(record=weapon3, fields='Name', value='Wand') #I find this easier to spot.
Run Code Online (Sandbox Code Playgroud)
如果你真的希望订单相同,但不要认为命名参数的想法足够清楚,那么如何使每个记录成为一个类似dict的项目而不是dict(如果它还没有)并且具有:
class Record:
...
def set_fields(self, *fields, value):
for f in fileds:
self[f] = value
weapon1.set_fields("Name", "ShortName", value="Dagger")
Run Code Online (Sandbox Code Playgroud)
这里唯一的问题是引入的类以及值参数必须使用关键字完成的事实,尽管它保持清晰.
或者,如果您使用的是Python 3,则始终可以选择使用扩展元组解包:
def set_fields(*args):
record, *fields, value = args
for f in fields:
record[f] = value
set_fields(weapon1, 'Name', 'ShortName', 'Dagger')
set_fields(weapon2, 'Name', 'Katana')
set_fields(weapon3, 'Name', 'Wand')
Run Code Online (Sandbox Code Playgroud)
或者,对于我的最后一个例子:
class Record:
...
def set_fields(self, *args):
*fields, value = args
for f in fileds:
self[f] = value
weapon1.set_fields("Name", "ShortName", "Dagger")
Run Code Online (Sandbox Code Playgroud)
但是,这些在读取函数调用时确实会留下一些奇怪的东西,因为人们通常认为参数不会以这种方式处理.
| 归档时间: |
|
| 查看次数: |
5033 次 |
| 最近记录: |