""" ============================ + +=
a+=a 和 a=a+a 虽然算数结果相同但是原理不同
a+=a        直接操作的是原来的a
a=a+a       是a+a计算完成以后重新分空间存新的列表[100, 100], 将地址赋值给一个新的局部变量a
"""

""" ============================ *
当序列里面是可变对象时 * 创建出来的序列包含的元素是同一个引用
"""

e = [['a'] * 3] * 3
print(e)  # [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
e[1][2] = 100
print(e)  # [['a', 'a', 100], ['a', 'a', 100], ['a', 'a', 100]]

# 列表推导式不是同一个引用
f = [['a'] * 3 for i in range(3)]
print(f)  # [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
f[1][2] = 100
print(f)  # [['a', 'a', 'a'], ['a', 'a', 100], ['a', 'a', 'a']]

""" ============================ += *= 
a += b
1. 会调用__iadd__方法, 与执行a.extend(b) 结果一样. 可变序列一般都实现了这个方法.
2. 如果没有实现__iadd__会执行__add__方法, 效果和 a = a + b 一样

a *= b
调用__imul__方法
1. 当对象时可变对象时修改原来的对象 
2. 不可变时创建新的对象, 效率低, 因为一位每次都创建新对象, 把元素复制到新对象在追加.
3. str是个特例除外
"""
# 可变对象
g = [1, 2, 3]
print(id(g), g)  # 4493844360 [1, 2, 3]
g *= 3
print(id(g), g)  # 4493844360 [1, 2, 3, 1, 2, 3, 1, 2, 3]

# 不可变对象
h = (1, 2, 3)
print(id(h), h)  # 4493317968 (1, 2, 3)
h *= 3
print(id(h), h)  # 4493772144 (1, 2, 3, 1, 2, 3, 1, 2, 3)

# str
i = 'name'
print(id(i), i)  # 4492293432 name
i *= 3
print(id(i), i)  # 4493738160 namenamename

# 可以存不同类型数据
a = [1, 33, "aaa"]
# 指定位置添加元素
a.insert(0, "aa")
# 删除指定元素
a.remove("aa")
# 删除索引元素
del a[1]

""" ============================ 列表推导式 """

# 返回新对象
[1, 2] * 2
[1, 2, 1, 2]

[[1, 2] * 2] * 3
[[1, 2, 1, 2], [1, 2, 1, 2], [1, 2, 1, 2]]

[i * 2 for i in range(20) if i % 3 == 2]
[4, 10, 16, 22, 28, 34]

d = [1, 2, 3]
e = [4, 5, 6]
# extend直接修改原来的，没有返回值
d.extend(e)
[1, 2, 3, 4, 5, 6]
# 返回新的list
f = d + e
[1, 2, 3, 4, 5, 6, 4, 5, 6]

[(i, j) for i in range(3) for j in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

[(i, j, k) for i in range(2) for j in range(2) for k in range(2)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]

k = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
l = [n for m in k for n in m]  # [1, 2, 3, 4, 5, 6, 7, 8, 9]
o = [[n * 2 for n in m] for m in k]  # [[2, 4, 6], [8, 10, 12], [14, 16, 18]]

""" ============================ 多个列表推导式 """

new_list2 = [(a, b, c) for a in '12' for b in 'ab' for c in '-=']
print(new_list2)

""" ============================ 推导式影响同名变量 (只影响python2)"""

item = 'abcd'
new_list = [item for item in '123']
print(item, new_list)  # abcd ['1', '2', '3']

""" ============================ range 
range的风险
python2中直接生成列表，不管是否使用。如果range(1,10000000000000000)计算机可能不给分配这么多内存。而且分配了内存但是没有使用，浪费资源
python3中为了解决这个问题机制改了，什么时候用什么时候生成，用一个创建一个。

xrange
"""

range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

range(10, 18)
[10, 11, 12, 13, 14, 15, 16, 17]

range(10, 18, 2)
[10, 12, 14, 16]

range(10, 18, 3)
[10, 13, 16]

for index, value in enumerate(['one', 'two', 'three']):
    print(index, value)

""" ============================ in 和 __contains__ 
in将调用对象的__contains__方法
对于列表，这是预定义的，也可以定义自己的类，添加contains方法并在该类的实例上使用in。 应该使用in而不是直接调用__contains__
如果未定义__contains__，则使用__getitem__。
"""
contains_list = [1, 2, 3, 4, 'aa']
print('aa' in contains_list)
print(contains_list.__contains__('aa'))

""" ============================ 拷贝原来的列表 """
c = [1, 2, 3, 4, 5, 6]
d = c[-0:]
print(c is d, d)  # False [1, 2, 3, 4, 5, 6]
e = c[:]
print(c is e, e)  # False [1, 2, 3, 4, 5, 6]
f = ['a', 'b', 'c']
f[:] = c
print(c is f, f)  # False [1, 2, 3, 4, 5, 6]

""" ============================ 切片范围可以不同 """
# [1, 2, 7, 8, 9, 10, 11, 4, 5, 6]
c[2:4] = [7, 8, 9, 10, 11]
# [1, 2, 1, 9, 10, 11, 5, 6]
c[2:4] = [1]
# [1, 2, 6]
del c[2:7]

""" ============================ 从任意可迭代对象中分解元素 (python3)
不定长使用 *
"""
list_01 = [1, 2, 3, 4, 5]
l1, *l2, l3 = list_01
print(l1, l2, l3)

4c7157f52d7f1fef03b6280843fb98b264b4df95
<mask token>

<mask token>
print(e)
<mask token>
print(e)
<mask token>
print(f)
<mask token>
print(f)
<mask token>
print(id(g), g)
g *= 3
print(id(g), g)
<mask token>
print(id(h), h)
h *= 3
print(id(h), h)
<mask token>
print(id(i), i)
i *= 3
print(id(i), i)
<mask token>
a.insert(0, 'aa')
a.remove('aa')
del a[1]
<mask token>
[1, 2] * 2
[1, 2, 1, 2]
[[1, 2] * 2] * 3
[[1, 2, 1, 2], [1, 2, 1, 2], [1, 2, 1, 2]]
[(i * 2) for i in range(20) if i % 3 == 2]
[4, 10, 16, 22, 28, 34]
<mask token>
d.extend(e)
[1, 2, 3, 4, 5, 6]
<mask token>
[1, 2, 3, 4, 5, 6, 4, 5, 6]
[(i, j) for i in range(3) for j in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
[(i, j, k) for i in range(2) for j in range(2) for k in range(2)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0
    ), (1, 1, 1)]
<mask token>
print(new_list2)
<mask token>
print(item, new_list)
<mask token>
range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(10, 18)
[10, 11, 12, 13, 14, 15, 16, 17]
range(10, 18, 2)
[10, 12, 14, 16]
range(10, 18, 3)
[10, 13, 16]
for index, value in enumerate(['one', 'two', 'three']):
    print(index, value)
<mask token>
print('aa' in contains_list)
print(contains_list.__contains__('aa'))
<mask token>
print(c is d, d)
<mask token>
print(c is e, e)
<mask token>
print(c is f, f)
<mask token>
del c[2:7]
<mask token>
print(l1, l2, l3)

<mask token>
e = [['a'] * 3] * 3
print(e)
e[1][2] = 100
print(e)
f = [(['a'] * 3) for i in range(3)]
print(f)
f[1][2] = 100
print(f)
<mask token>
g = [1, 2, 3]
print(id(g), g)
g *= 3
print(id(g), g)
h = 1, 2, 3
print(id(h), h)
h *= 3
print(id(h), h)
i = 'name'
print(id(i), i)
i *= 3
print(id(i), i)
a = [1, 33, 'aaa']
a.insert(0, 'aa')
a.remove('aa')
del a[1]
<mask token>
[1, 2] * 2
[1, 2, 1, 2]
[[1, 2] * 2] * 3
[[1, 2, 1, 2], [1, 2, 1, 2], [1, 2, 1, 2]]
[(i * 2) for i in range(20) if i % 3 == 2]
[4, 10, 16, 22, 28, 34]
d = [1, 2, 3]
e = [4, 5, 6]
d.extend(e)
[1, 2, 3, 4, 5, 6]
f = d + e
[1, 2, 3, 4, 5, 6, 4, 5, 6]
[(i, j) for i in range(3) for j in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
[(i, j, k) for i in range(2) for j in range(2) for k in range(2)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0
    ), (1, 1, 1)]
k = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
l = [n for m in k for n in m]
o = [[(n * 2) for n in m] for m in k]
<mask token>
new_list2 = [(a, b, c) for a in '12' for b in 'ab' for c in '-=']
print(new_list2)
<mask token>
item = 'abcd'
new_list = [item for item in '123']
print(item, new_list)
<mask token>
range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(10, 18)
[10, 11, 12, 13, 14, 15, 16, 17]
range(10, 18, 2)
[10, 12, 14, 16]
range(10, 18, 3)
[10, 13, 16]
for index, value in enumerate(['one', 'two', 'three']):
    print(index, value)
<mask token>
contains_list = [1, 2, 3, 4, 'aa']
print('aa' in contains_list)
print(contains_list.__contains__('aa'))
<mask token>
c = [1, 2, 3, 4, 5, 6]
d = c[-0:]
print(c is d, d)
e = c[:]
print(c is e, e)
f = ['a', 'b', 'c']
f[:] = c
print(c is f, f)
<mask token>
c[2:4] = [7, 8, 9, 10, 11]
c[2:4] = [1]
del c[2:7]
<mask token>
list_01 = [1, 2, 3, 4, 5]
l1, *l2, l3 = list_01
print(l1, l2, l3)

""" ============================ + +=
a+=a 和 a=a+a 虽然算数结果相同但是原理不同
a+=a        直接操作的是原来的a
a=a+a       是a+a计算完成以后重新分空间存新的列表[100, 100], 将地址赋值给一个新的局部变量a
"""

""" ============================ *
当序列里面是可变对象时 * 创建出来的序列包含的元素是同一个引用
"""

e = [['a'] * 3] * 3
print(e)  # [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
e[1][2] = 100
print(e)  # [['a', 'a', 100], ['a', 'a', 100], ['a', 'a', 100]]

# 列表推导式不是同一个引用
f = [['a'] * 3 for i in range(3)]
print(f)  # [['a', 'a', 'a'], ['a', 'a', 'a'], ['a', 'a', 'a']]
f[1][2] = 100
print(f)  # [['a', 'a', 'a'], ['a', 'a', 100], ['a', 'a', 'a']]

""" ============================ += *= 
a += b
1. 会调用__iadd__方法, 与执行a.extend(b) 结果一样. 可变序列一般都实现了这个方法.
2. 如果没有实现__iadd__会执行__add__方法, 效果和 a = a + b 一样

a *= b
调用__imul__方法
1. 当对象时可变对象时修改原来的对象 
2. 不可变时创建新的对象, 效率低, 因为一位每次都创建新对象, 把元素复制到新对象在追加.
3. str是个特例除外
"""
# 可变对象
g = [1, 2, 3]
print(id(g), g)  # 4493844360 [1, 2, 3]
g *= 3
print(id(g), g)  # 4493844360 [1, 2, 3, 1, 2, 3, 1, 2, 3]

# 不可变对象
h = (1, 2, 3)
print(id(h), h)  # 4493317968 (1, 2, 3)
h *= 3
print(id(h), h)  # 4493772144 (1, 2, 3, 1, 2, 3, 1, 2, 3)

# str
i = 'name'
print(id(i), i)  # 4492293432 name
i *= 3
print(id(i), i)  # 4493738160 namenamename

# 可以存不同类型数据
a = [1, 33, "aaa"]
# 指定位置添加元素
a.insert(0, "aa")
# 删除指定元素
a.remove("aa")
# 删除索引元素
del a[1]

""" ============================ 列表推导式 """

# 返回新对象
[1, 2] * 2
[1, 2, 1, 2]

[[1, 2] * 2] * 3
[[1, 2, 1, 2], [1, 2, 1, 2], [1, 2, 1, 2]]

[i * 2 for i in range(20) if i % 3 == 2]
[4, 10, 16, 22, 28, 34]

d = [1, 2, 3]
e = [4, 5, 6]
# extend直接修改原来的，没有返回值
d.extend(e)
[1, 2, 3, 4, 5, 6]
# 返回新的list
f = d + e
[1, 2, 3, 4, 5, 6, 4, 5, 6]

[(i, j) for i in range(3) for j in range(2)]
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]

[(i, j, k) for i in range(2) for j in range(2) for k in range(2)]
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]

k = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
l = [n for m in k for n in m]  # [1, 2, 3, 4, 5, 6, 7, 8, 9]
o = [[n * 2 for n in m] for m in k]  # [[2, 4, 6], [8, 10, 12], [14, 16, 18]]

""" ============================ 多个列表推导式 """

new_list2 = [(a, b, c) for a in '12' for b in 'ab' for c in '-=']
print(new_list2)

""" ============================ 推导式影响同名变量 (只影响python2)"""

item = 'abcd'
new_list = [item for item in '123']
print(item, new_list)  # abcd ['1', '2', '3']

""" ============================ range 
range的风险
python2中直接生成列表，不管是否使用。如果range(1,10000000000000000)计算机可能不给分配这么多内存。而且分配了内存但是没有使用，浪费资源
python3中为了解决这个问题机制改了，什么时候用什么时候生成，用一个创建一个。

xrange
"""

range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

range(10, 18)
[10, 11, 12, 13, 14, 15, 16, 17]

range(10, 18, 2)
[10, 12, 14, 16]

range(10, 18, 3)
[10, 13, 16]

for index, value in enumerate(['one', 'two', 'three']):
    print(index, value)

""" ============================ in 和 __contains__ 
in将调用对象的__contains__方法
对于列表，这是预定义的，也可以定义自己的类，添加contains方法并在该类的实例上使用in。 应该使用in而不是直接调用__contains__
如果未定义__contains__，则使用__getitem__。
"""
contains_list = [1, 2, 3, 4, 'aa']
print('aa' in contains_list)
print(contains_list.__contains__('aa'))

""" ============================ 拷贝原来的列表 """
c = [1, 2, 3, 4, 5, 6]
d = c[-0:]
print(c is d, d)  # False [1, 2, 3, 4, 5, 6]
e = c[:]
print(c is e, e)  # False [1, 2, 3, 4, 5, 6]
f = ['a', 'b', 'c']
f[:] = c
print(c is f, f)  # False [1, 2, 3, 4, 5, 6]

""" ============================ 切片范围可以不同 """
# [1, 2, 7, 8, 9, 10, 11, 4, 5, 6]
c[2:4] = [7, 8, 9, 10, 11]
# [1, 2, 1, 9, 10, 11, 5, 6]
c[2:4] = [1]
# [1, 2, 6]
del c[2:7]

""" ============================ 从任意可迭代对象中分解元素 (python3)
不定长使用 *
"""
list_01 = [1, 2, 3, 4, 5]
l1, *l2, l3 = list_01
print(l1, l2, l3)
