【问题标题】:Python why would you use [:] over =Python 为什么要使用 [:] 而不是 =
【发布时间】:2013-01-04 05:16:19
【问题描述】:

我只是在学习 python,我正在学习 https://developers.google.com/edu/python/strings 上的教程

字符串切片部分下

s[:] is 'Hello' -- 省略两者总是给我们一个整体的副本 事情(这是复制字符串之类的序列或 列表)

出于好奇,您为什么不直接使用= 运算符?

s = 'hello';
bar = s[:] 
foo = s 

据我所知,barfoo 具有相同的值。

【问题讨论】:

  • 我不同意这句话,这不是复制字符串的pythonic方式。你是正确的,你只会使用=。对于列表,情况就不同了。

标签: python python-3.x


【解决方案1】:

= 进行引用,通过使用 [:] 创建一个副本。对于不可变的字符串,这并不重要,但对于列表等来说,这至关重要。

>>> s = 'hello'
>>> t1 = s
>>> t2 = s[:]
>>> print s, t1, t2
hello hello hello
>>> s = 'good bye'
>>> print s, t1, t2
good bye hello hello

但是:

>>> li1 = [1,2]
>>> li = [1,2]
>>> li1 = li
>>> li2 = li[:]
>>> print li, li1, li2
[1, 2] [1, 2] [1, 2]
>>> li[0] = 0
>>> print li, li1, li2
[0, 2] [0, 2] [1, 2]

那么为什么在处理字符串时使用它呢? 内置字符串是不可变的,但是每当你编写一个期望字符串的库函数时,用户可能会给你一些“看起来像字符串”的东西" 和 "表现得像一个字符串",但是是一个自定义类型。这种类型可能是可变的,所以最好注意这一点。

这样的类型可能看起来像:

class MutableString(object):
    def __init__(self, s):
        self._characters = [c for c in s]

    def __str__(self):
        return "".join(self._characters)

    def __repr__(self):
        return "MutableString(\"%s\")" % str(self)

    def __getattr__(self, name):
        return str(self).__getattribute__(name)

    def __len__(self):
        return len(self._characters)

    def __getitem__(self, index):
        return self._characters[index]

    def __setitem__(self, index, value):
        self._characters[index] = value

    def __getslice__(self, start, end=-1, stride=1):
        return str(self)[start:end:stride]


if __name__ == "__main__":
    m = MutableString("Hello")
    print m
    print len(m)
    print m.find("o")
    print m.find("x")
    print m.replace("e", "a") #translate to german ;-)
    print m
    print m[3]
    m[1] = "a"
    print m
    print m[:]

    copy1 = m
    copy2 = m[:]
    print m, copy1, copy2
    m[1] = "X"
    print m, copy1, copy2

免责声明:这只是一个示例,用于展示它如何工作并鼓励使用[:]。它未经测试、不完整且性能可能非常糟糕

【讨论】:

  • 请告诉我你已经有这样的课程了,并没有把整个事情放在一起只是为了这样的答案:)
  • 对不起,我不得不让你失望 ;-) 如果你查看我的回答的提交历史,你可以看到它在增长。
  • 在任意对象上使用[:] 并不能保证您获得副本。例如,NumPy 数组返回原始可变数据的视图。一个自定义的可变字符串类可能会做同样的事情。
  • 当然,您通常有copy-module 或特定方法。我从来没有说过[:] 为任何可下标对象创建一个副本,仅对于内置类型,这是 True。然而,如果你曾经编写一个自定义的类似字符串的类型并想将它用作期望字符串的函数的参数,那么你绝对应该让你的类型表现得像一个字符串。这包括[:] 上的行为。这就是鸭式打字的原理。如果你不坚持这一点,你最好有充分的理由这样做。
【解决方案2】:

它们具有相同的值,但在处理可变对象时存在根本区别。

foo = [1, 2, 3]。您分配 bar = foobaz = foo[:]。现在假设您要更改 bar - bar.append(4)。你检查foo的值,然后...

print foo
# [1, 2, 3, 4]

那么额外的4 是从哪里来的?这是因为您将bar 分配给foo身份,所以当您更改一个时,您会更改另一个。您更改了baz - baz.append(5),但其他两个没有发生任何事情 - 这是因为您将foo一个副本分配给了baz

但是请注意,因为字符串是不可变的,所以没关系。

【讨论】:

    【解决方案3】:

    如果你有一个列表,结果会有所不同:

    l = [1,2,3]
    l1 = l
    l2 = l[:]
    

    l2 是 l(不同对象)的副本,而 l1 是 l 的别名,这意味着 l1[0]=7 也会修改 l,而 l2[1]=7 不会修改 l。

    【讨论】:

      【解决方案4】:

      虽然引用对象和引用对象的副本对于像字符串这样的不可变对象没有区别,但它们对于可变对象(和可变方法),例如列表。

      可变对象也是如此:

      a = [1,2,3,4]
      b = a
      c = a[:]
      a[0] = -1
      print a    # will print [1,2,3,4]
      print b    # will print [-1,2,3,4]
      print c    # will print [1,2,3,4]
      

      上述示例的pythontutor上的可视化 - http://goo.gl/Aswnl.

      【讨论】:

      • a 会打印出 [-1, 2, 3, 4]
      猜你喜欢
      • 1970-01-01
      • 2013-12-07
      • 2015-05-03
      • 2011-10-09
      • 2013-09-13
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多