Interesting in python(2)
brackets,Multiplication sign,backslash,Equal sign,Quotation marks
括号,乘号,反斜杠,判等号,引号
小括号与中括号
is not and is (not ...)
@python 3.6.7
this = 'this'
print(this is not None) # True
print(this is (not None)) #False
上面应该很好理解,加了括号的not None
is True
。
列表生成式与生成器表达式
@python3.6.7
list1 = [1, 2, 3]
t1 = (x for x in list1 if list1.count(x) > 0) # iterator
list1 = [4, 2, 5]
print(list(t1))
# result
# [2]
list2 = [1, 2, 3]
t2 = [x for x in list2 if list2.count(x) > 0] # list
list2 = [4, 2, 5]
print(t2)
# result
# [1, 2, 3]
在上面中代码中,我们对列表list1,list2分别进行生成器操作和列表生成后都立马进行了重新赋值,但生成器的结果好像有点出乎意料。
这是因为在生成器表达式中,in
子句在声明时执行,所以用来比较的x
还是1,2,3
;而if
条件子句则在运行时执行,所以此时条件判断中list1已经变成了[4,2,5]
,能够判断成功的就只有2
了,而在列表生成式中则不受影响。
另外一种情况:
@python 3.6.7
list1 = [1, 2, 3]
t1 = (x for x in list1) # iterator
list1 = [1, 2, 3, 4]
print(list(t1))
# 两个list1不是同一个对象
# result
# [1, 2, 3]
list2 = [1, 2, 3]
t2 = (x for x in list2) # iterator
list2[:] = [1, 2, 3, 4]
print(list(t2))
# 由于切片操作赋值给相同的旧对象,两个list2是同一个对象
# result
# [1, 2, 3, 4]
list2 = [1, 2, 3]
print(id(list2))
t2 = [x for x in list2] # list
list2[:] = [1, 2, 3, 4]
print(id(list2))
print(list(t2))
# 两个list2是同一个对象,但用列表生成式就不会O(∩_∩)O哈哈~
# result
# 139771935690440
# 139771935690440
# [1, 2, 3]
这里好像与我们之前说的in
在声明的时候执行有点冲突,但其实不然,in
确实是在声明的时候就执行,这句话意思是上面代码中赋值给x
的是以前的list
对象。所以当两个list
对象不同时,结果是原来list
对象的值;而切片操作是赋值给原来的对象,in
也操作原来的对象,所以就变成了赋值后的结果了。
我们简单总结一下,实际上如果用列表生成式,那么后一行代码的操作不会影响它的执行结果,即使是改变同一个对象,因为列表生成式在这行代码之后就已经完成;而生成器表达式的in
子句会使用同一个对象,若改变同一对象就会对in
造成影响,if
条件子句则在执行时会受后面代码改动的影响,不管是否改动的是同一对象。因此我们可以大胆的写出以下代码来进行验证:
@python 3.6.7
old_list = [1, 2, 3] # 1
t = (x for x in old_list if old_list.count(x) > 0)
old_list[:] = [4, 5, 6] # 2
print(list(t))
# 因为切片,old_list原有对象被重新赋值,对象不变
# 所以in使用的是: # 2 注释的old_list的值
# if进行判断使用的也是: # 2 注释的old_list的值
# 所以 result
# [4, 5, 6]
所以当我们在使用生成器表达式时,如果为了节省变量名而随意在生成器表达式后面改动变量原来的值就很容易造成一些意想不到的结果。但也不要因此就不使用生成器,毕竟对于数量庞大的列表改用生成器是非常划算的,我们需要注意的只是命名规范和编码习惯,不要轻易改变原来已经存在对象的值。
方便的乘号 *
?
@python 3.6.7
single = [''] * 3 # single ['', '', '']
double = [single] * 2
# double [['', '', ''], ['', '', '']]
print(double[0][0]) # empty
double[0][0] = 'x'
print(double)
# result
# [['x', '', ''], ['x', '', '']]
为啥明明我们只赋值了一个值,但是有两个位置都有x
呢?
那是因为当我们使用乘号的进行快速创建列表时,实际上只是增加了double
中single
的引用,即double[0]
,double[1]
引用的是同一个对象。
@python 3.6.7
single = [''] * 3
double = [single] * 2
print(id(double[0]), id(double[1]))
print(double[0] is double[1])
# result
# 140063679369736 140063679369736
# True
所以毫无疑问赋值double[0][0]
实际上也是在对double[1][0]
进行操作。那么我们该如何消除这种影响,而做到我们真正想要的呢?下面有一种巧妙的办法,就是不用中间变量进行引用。
@python 3.6.7
double = [[''] * 3 for _ in range(2)]
double[0][0] = 'x'
print(double)
# result
# [['x', '', ''], ['', '', '']]
反斜杠转义和打印反斜杠
众所周知,反斜杠会对后面的字符进行转移,所以\n
代表换行,\r
代表回车,那么如何打印字符串\n
呢?再加上一个反斜杠是很好的选择。
@python 3.6.7
newline = '\\n'
print(newline)
# result
# \n
也可以使用下面的方法:
@python 3.6.7
newline = r'\n'
print(newline)
# result
# \n
但是请注意不要这样使用:
@python 3.6.7
print(r'\n\') # SyntaxError
因为在以r
开头的原始字符串中,解释器改变了反斜杠会解释后面一个字符的行为,取而代之的是直接放行反斜杠后面的一个字符,所以上面的最后一个单引号被视为要打印的一部分。如果非要这样使用,正确的写法应该是这样的:
@python 3.6.7
print(r'\n\'') # 再添加一个单引号
# result
# \n\'
小心运算符的优先级
@python 3.6.7
x = True
y = False
print(not x == y) # True
print(x == not y) # SyntaxError
因为在python中==
运算符的优先级要高于not
运算符。所以not x == y
等价于not (x == y)
为True
;而x == not y
等价于(x == not) y
所以语法错误。
是拼接还是注释
我们都知道python多行注释以三个引号为标记,但有些时候这只是字符串拼接。
@python 3.6.7
"""This is comment."""
print('''hello''') # hello
print("""hello again""") # hello again
print('hello''') # hello
print("hello again""") # hello again
print('''hello') # SyntaxError
print("""hello again") # SyntaxError
如果你的编辑器有代码高亮,实际上你已经可以看到不同之处。三个引号在前,那么解释器会试图再寻找三个相同的引号作为定界符,将其视为注释或者可打印的字符串。而如果三个引号在后,实际上是隐式的字符串连接,'hello'''
意味着'hello' ''
,拼接一个空字符串,因此可以正确打印。
网友评论