【一日一技】揭秘字符串的两副“面孔”

如果你经常在python的命令行交互环境中工作,你可能会注意到以下现象:

a = 'test'

a

'test'

print(a)

test

首先,我们定义了一个变量a,值为字符串'test'。

当你直接在命令行输入变量名a并回车时,显示的结果是'test',而使用print(a)时,显示的结果则是test。

直接输入变量名并回车,字符串会被单引号包围。而使用print函数打印变量时,字符串则不带引号。

虽然引号看起来只是一个小问题,但让我们看看反斜杠的情况:

b = 'D:\game\pal4'

b

'D:\\game\\pal4'

print(b)

D:\game\pal4

这里,变量b的值是一个Windows路径。在定义时,我使用的是单个反斜杠。

当我直接输入变量名b并回车时,结果是'D:\\game\\pal4',不仅有最外层的引号,而且反斜杠变成了双反斜杠。

但当我使用print函数打印时,一切又恢复正常。

这看起来很奇怪,对吗?

实际上,直接输入变量名并回车时,你看到的是字符串在Python中的真实样子,因为在Python中不存在单个反斜杠。要表示反斜杠本身,必须使用\\这种形式。

当然,在定义时你可以只写单个反斜杠,Python通常会理解你的意图,并自动将单个反斜杠转换为双反斜杠。

而使用print函数打印出来的,是Python优化后更易于人类阅读的形式。

当然,通过修改print函数,你也可以看到字符串的真实样子:

b = 'D:\game\pal4'

b

'D:\\game\\pal4'

print(repr(b))

'D:\\game\\pal4'

当你使用repr函数处理字符串后再打印时,效果与直接输入变量名并回车相同。

在Python中,repr(对象)本质上是调用了对象的repr方法。而直接print(对象)时,打印的是对象的str方法返回的内容。

让我们做一个实验:

class Test:
    def __repr__(self):
        return 'hello world!'

    def __str__(self):
        return '为什么我总是对你说你好,因为你是我的世界啊,傻瓜'

you = Test()

动手测试一下,输入you然后直接回车显示的是什么内容。输入print(you)显示的又是什么内容。

运行效果图

从上面的例子可以看出,直接输入变量名回车和直接使用print函数打印调用的是对象的不同方法。所以它们当然可以不同。

回到昨天的问题,在PyCharm的调试模式中,你看到的内容实际上是变量对象的repr方法返回的内容,这里显示的是字符串在Python中的真实样子,因此斜杠会变多。

前面提到,当你输入Windows路径时,Python通常能理解你的意图,将单个反斜杠转换为双反斜杠。不过也有例外情况。

例如:

假设有一个名为u6211的文件夹,它位于pal4文件夹中。

那么,路径应该是:D:\game\pal4\u6211

如果在Python中执行,会出现什么问题?

c = 'D:\game\pal4\u6211'

c

'D:\\game\\pal4我'

print(c)

D:\game\pal4我

为什么u6211和前面的pal4拼在一起了?

因为\u6211是一个Unicode编码,表示中文字符“我”。

在这种情况下,你有两种解决方法:

1. 手动使用双反斜杠:

b = 'D:\game\pal4\\u6211'

b

'D:\\game\\pal4\\u6211'

print(b)

D:\game\pal4\u6211

2. 在定义变量时,在字符串左侧引号前加上字母r:

b = r'D:\game\pal4\u6211'

b

'D:\\game\\pal4\\u6211'

print(b)

D:\game\pal4\u6211