专栏首页浊酒清味你一定遇到过Python中的无效语法:SyntaxError---常见原因以及解决办法

你一定遇到过Python中的无效语法:SyntaxError---常见原因以及解决办法

Python以其简单的语法而闻名。然而,当您第一次学习Python时,或者当您具有另一种编程语言的坚实背景时,您可能会遇到一些Python不允许的事情。如果您在尝试运行Python代码时收到过SyntaxError错误,那么本指南可以帮助您。在本教程中,您将看到Python中常见的无效语法示例,并学习如何解决这个问题。

在本教程结束时,您将能够:

  • 识别Python中的无效语法
  • 理解SyntaxError回溯
  • 解析无效语法或完全阻止它

Python中的无效语法

当您运行Python代码时,解释器将首先解析它,将其转换成Python字节码,然后执行。解释器将在程序执行的第一阶段(也称为解析阶段)中发现Python中的任何无效语法。如果解释器不能成功地解析您的Python代码,那么这意味着您在代码的某个地方使用了无效的语法。解释器将尝试向您显示错误发生的位置。

当您第一次学习Python时,得到一个SyntaxError可能会令人沮丧。Python将尝试帮助您确定无效语法在代码中的位置,但是它提供的回溯可能会让您感到有些困惑。有时,它所指向的代码是完全正确的。

您不能像处理其他异常一样处理Python中的无效语法。即使您尝试将try和except块封装到带有无效语法的代码中,您仍然会看到解释器抛出一个SyntaxError。

SyntaxError异常和回溯

当解释器在Python代码中遇到无效语法时,它将抛出一个SyntaxError异常,并提供一个带有一些有用信息的回溯,以帮助您调试错误。下面是一些Python中包含无效语法的代码:

 1 # theofficefacts.py
 2 ages = {
 3     'pam': 24,
 4     'jim': 24
 5     'michael': 43
 6 }
 7 print(f'Michael is {ages["michael"]} years old.')

您可以在第4行字典的文字中看到无效的语法。第二个词条“jim”漏掉了一个逗号。如果你试着按原样运行这段代码,你会得到以下回溯结果:

$ python theofficefacts.py
File "theofficefacts.py", line 5
    'michael': 43
            ^
SyntaxError: invalid syntax

注意,traceback消息定位的错误在第5行,而不是第4行。Python解释器试图指出无效语法的位置。然而,它只能指出它最初注意到的问题。当您获得一个SyntaxError traceback,并且traceback所指向的代码看起来很好,那么您将希望开始向后移动代码,直到您能够确定哪里出了问题。

在上面的例子中,根据后面的内容,省略逗号是没有问题的。例如,第5行“michael”后面缺少逗号是没有问题的。但是一旦解释器遇到不理解的东西,它只能指出它发现的第一件不理解的事情。

回溯是一个堆栈跟踪,从异常处理程序的点一直到调用链中的异常引发点。您还可以从调用的角度(并且没有错误的上下文)向上使用当前调用堆栈,这对于查找函数所遵循的路径非常有用。

有几个元素的SyntaxError回溯,可以帮助您确定无效的语法在您的代码:

  • 遇到无效语法的文件名
  • 遇到问题的行号和代码的复写行
  • 在复制代码下面的行中有一个插入符号(^),它向您显示代码中有问题的那一点
  • 异常类型SyntaxError之后的错误消息,可以提供帮助您确定问题的信息

在上面的例子中,给出的文件名是theofficefacts。行号为5,插入符号指向字典键michael的结束引用。SyntaxError回溯可能不会指向真正的问题,但它将指向解释器无法理解语法的第一个地方。

您可能会看到Python引发另外两个异常。它们等价于SyntaxError,但有不同的名称:

  1. IndentationError
  2. TabError

这些异常都继承自SyntaxError类,但它们是涉及缩进的特殊情况。当代码的缩进级别不匹配时,将引发IndentationError。当代码在同一文件中同时使用制表符和空格时,将引发一个制表符错误。在后面的小节中,您将进一步了解这些异常。

常见的语法问题

当您第一次遇到SyntaxError时,了解为什么会出现问题以及如何修复Python代码中的无效语法是很有帮助的。在下面的小节中,您将看到可能引发SyntaxError的一些更常见的原因,以及如何修复它们。

01

误用赋值运算符(=)

在Python中有几种情况下,您不能对对象进行赋值。一些例子是分配文字和函数调用。在下面的代码块中,您可以看到一些尝试这样做的示例和由此产生的SyntaxError回溯:

>>>

>>> len('hello') = 5
  File "<stdin>", line 1
SyntaxError: can't assign to function call

>>> 'foo' = 1
  File "<stdin>", line 1
SyntaxError: can't assign to literal

>>> 1 = 'foo'
  File "<stdin>", line 1
SyntaxError: can't assign to literal

第一个示例尝试将值5分配给len()调用。在这种情况下,SyntaxError消息非常有用。它告诉你不能给函数调用赋值。

第二个和第三个示例尝试将字符串和整数分配给文字。同样的规则也适用于其他文字值。同样,回溯消息表明,当您试图将一个值赋给一个文字时,问题就会发生。

注意:上面的示例缺少重复的代码行和指向回溯中的问题的插入符号(^)。当您在REPL中尝试从文件中执行这段代码时,您看到的异常和回溯将是不同的。如果这个代码在一个文件中,那么您将得到重复的代码行和指向问题的插入符号,正如您在本教程的其他情况中看到的那样。

很可能你的目的不是给文字或函数调用赋值。例如,如果您不小心省略了额外的等号(=),就会发生这种情况,这会将赋值转换为比较。如下所示,比较是有效的:

>>>

>>> len('hello') == 5
True

大多数情况下,当Python告诉您正在对无法赋值的东西进行赋值时,您首先可能需要检查以确保语句不应该是布尔表达式。当您试图为Python关键字赋值时,也可能遇到这个问题,下一节将讨论这个问题。

02

拼写错误、缺少或误用Python关键字

Python关键字是一组在Python中具有特殊含义的受保护的单词。这些词在代码中不能用作标识符、变量或函数名。它们是语言的一部分,只能在Python允许的上下文中使用。

有三种常见的方式,你可以错误地使用关键字:

  1. 拼错的关键字
  2. 缺少一个关键字
  3. 滥用关键字

如果您在Python代码中拼错了关键字,那么您将得到一个SyntaxError。例如,如果你把关键字拼错了,会发生以下情况:

>>> fro i in range(10):
  File "<stdin>", line 1
    fro i in range(10):
        ^
SyntaxError: invalid syntax

消息将读取SyntaxError:无效语法,但这没有多大帮助。回溯指向Python可以检测到错误的第一个地方。要修复这类错误,请确保所有Python关键字拼写正确。

另一个关于关键字的常见问题是你完全忽略了它们:

>>>

>>> for i range(10):
  File "<stdin>", line 1
    for i range(10):
              ^
SyntaxError: invalid syntax

同样,异常消息也不是很有用,但是回溯确实试图为您指出正确的方向。如果从插入符号返回,则可以看到for循环语法中缺少关键字in。

您还可能误用受保护的Python关键字。记住,关键字只允许在特定的情况下使用。如果您不正确地使用它们,那么您的Python代码中就会出现无效的语法。一个常见的例子是在循环外使用continue或break。这在开发过程中很容易发生,当你在实现一些东西的时候,碰巧把逻辑移出了一个循环:

>>> names = ['pam', 'jim', 'michael']
>>> if 'jim' in names:
...     print('jim found')
...     break
...
  File "<stdin>", line 3
SyntaxError: 'break' outside loop

>>> if 'jim' in names:
...     print('jim found')
...     continue
...
  File "<stdin>", line 3
SyntaxError: 'continue' not properly in loop

在这里,Python很好地告诉了您到底哪里出了问题。"'break' outside loop"和" continue' not exactly in loop"这两个信息可以帮助你明确地知道该怎么做。如果这段代码在一个文件中,那么Python也会让插入符号指向被误用的关键字。

另一个例子是,如果你尝试给一个变量分配一个Python关键字,或者使用一个关键字来定义一个函数:

>>>

>>> pass = True
  File "<stdin>", line 1
    pass = True
         ^
SyntaxError: invalid syntax
>>> def pass():
  File "<stdin>", line 1
    def pass():
           ^
SyntaxError: invalid syntax

当您试图为pass分配一个值时,或者当您试图定义一个名为pass的新函数时,您将得到一个SyntaxError并再次看到“无效语法”消息。

在Python代码中解决这种类型的无效语法可能会稍微困难一些,因为代码从外部看起来没什么问题。如果您的代码看起来不错,但是您仍然会得到一个SyntaxError,那么您可以考虑检查您想要使用的变量名或函数名与您正在使用的Python版本的关键字列表。

受保护的关键字列表随着Python的每个新版本而改变。例如,在Python 3.6中,您可以使用await作为变量名或函数名,但是在Python 3.7中,这个单词已经被添加到关键字列表中。现在,如果您尝试使用await作为变量名或函数名,如果您的代码是Python 3.7或更高版本,那么这将导致SyntaxError。

另一个例子是print,它在python2和python3中有所不同:

Version

print Type

Takes A Value

Python 2

keyword

no

Python 3

built-in function

yes

print是python2中的一个关键字,所以你不能给它赋值。然而,在python3中,它是一个可以赋值的内置函数。

你可以运行以下代码来查看关键字列表,无论你运行的Python版本是什么:

import keyword
print(keyword.kwlist)yword.iskey

keyword还提供了有用的keyword.iskeyword()。如果你只是需要一个快速的方法来检查通过变量,那么你可以使用以下一行:

>>> import keyword; keyword.iskeyword('pass')
True

这段代码将快速告诉您要使用的标识符是否是关键字。

03

缺少括号、方括号和引号

通常,Python代码中无效语法的原因是缺少或不匹配的右括号、方括号或引号。在嵌套圆括号的很长行或更长的多行块中很难发现这些。你可以通过Python的回溯来发现不匹配或缺失的引用:

>>>

>>> message = 'don't'
  File "<stdin>", line 1
    message = 'don't'
                   ^
SyntaxError: invalid syntax

这里,回溯指向无效代码,其中在结束单引号后有一个t'。要解决这个问题,您可以进行以下两种更改之一:

  1. 用反斜杠转义单引号('don\t')
  2. 将整个字符串用双引号括起来(“don't”)

另一个常见的错误是忘记关闭字符串。对于双引号和单引号字符串,情况和回溯是相同的:

>>>

>>> message = "This is an unclosed string
  File "<stdin>", line 1
    message = "This is an unclosed string
                                        ^
SyntaxError: EOL while scanning string literal

这一次,traceback中的插入符号指向问题代码。SyntaxError消息“在扫描字符串文字时的EOL”更具体一些,有助于确定问题。这意味着Python解释器在一个开放字符串关闭之前到达该行(EOL)的末尾。要解决这个问题,请使用与开始时匹配的引号关闭字符串。在本例中,将使用双引号(")。

在f-string语句中缺少引号也会导致Python中无效的语法:

 1 # theofficefacts.py
 2 ages = {
 3     'pam': 24,
 4     'jim': 24,
 5     'michael': 43
 6 }
 7 print(f'Michael is {ages["michael]} years old.')

这里,打印的f-string中对ages字典的引用缺少关键引用的双引号。得到的回溯结果如下:

$ python theofficefacts.py
  File "theofficefacts.py", line 7
    print(f'Michael is {ages["michael]} years old.')
         ^
SyntaxError: f-string: unterminated string

Python识别问题并告诉您它存在于f-string中。消息“未终止字符串”也指出了问题所在。本例中的插入符号仅指向f-string的开头。

当插入符号指向f-string的问题区域时,这可能没有那么有用,但是它确实缩小了您需要查找的范围。在那个f字串的某个地方有一个未终止的字符串。你只需要找到在哪里。要修复此问题,请确保所有内部f-string引号和方括号都已存在。

缺少括号和方括号的情况大致相同。例如,如果您从列表中删除了右方括号,那么Python将会发现并指出它。然而,这有一些变化。第一种是把列表中的右括号去掉:

# missing.py
def foo():
    return [1, 2, 3

print(foo())

当你运行这段代码时,你会被告知调用print()有一个问题:

$ python missing.py
  File "missing.py", line 5
    print(foo())
        ^
SyntaxError: invalid syntax

这里发生的是Python认为列表包含三个元素:1、2和3 print(foo())。Python使用空格从逻辑上对事物进行分组,因为从print(foo())中没有逗号或括号分隔3,所以Python将它们集中在一起作为列表的第三个元素。

另一种变化是在列表的最后一个元素后面添加一个逗号,同时仍然去掉右方括号:

# missing.py
def foo():
    return [1, 2, 3,

print(foo())

现在你得到了一个不同的回溯:

$ python missing.py
  File "missing.py", line 6

                ^
SyntaxError: unexpected EOF while parsing

在前面的例子中,3和print(foo())被集中在一起作为一个元素,但是在这里你可以看到一个逗号将两者分开。现在,print(foo())的调用被添加为列表的第四个元素,Python到达了文件的末尾,但没有使用右括号。回溯告诉您,Python已经到达了文件(EOF)的末尾,但是它还在期待其他内容。

在本例中,Python希望有一个右括号(]),但是重复的行和插入符号没有多大帮助。缺少括号和方括号是Python很难识别的。有时,您唯一能做的就是从插入符号开始,然后向后移动,直到您能够识别出缺失或错误的地方。

04

字典语法错误

您在前面已经看到,如果将dictionary元素中的逗号去掉,可能会得到SyntaxError。Python字典的另一种无效语法形式是使用等号(=)来分隔键和值,而不是冒号:

>>>

>>> ages = {'pam'=24}
  File "<stdin>", line 1
    ages = {'pam'=24}
                 ^
SyntaxError: invalid syntax

同样,这个错误消息不是很有用。但是,重复的行和插入符号非常有用!他们直接指向问题人物。

如果您将Python语法与其他编程语言的语法混淆,那么这种类型的问题很常见。如果将定义字典的行为与dict()调用相混淆,也会看到这种情况。要解决这个问题,可以用冒号替换等号。你也可以切换到使用dict():

>>>

>>> ages = dict(pam=24)
>>> ages
{'pam': 24}

如果dict()语法更有帮助,那么可以使用它来定义字典。

05

使用错误的缩进

SyntaxError有两个子类专门处理缩进问题:

  1. IndentationError
  2. TabError

其他编程语言使用花括号表示代码块,而Python使用空格。这意味着Python期望代码中的空白具有可预测性。如果代码块中有一行空格数错误,则会引发IndentationError:

 1 # indentation.py
 2 def foo():
 3     for i in range(10):
 4         print(i)
 5   print('done')
 6
 7 foo()

这可能很难看到,但是第5行只缩进了2个空格。它应该与for循环语句一致,也就是4个空格。幸运的是,Python可以很容易地发现这一点,并很快告诉您问题所在。

不过这里也有一点模糊。打印('done')行是打算在for循环之后还是在for循环块内部?当你运行上述代码,你会看到以下错误:

$ python indentation.py
  File "indentation.py", line 5
    print('done')
                ^
IndentationError: unindent does not match any outer indentation level

虽然回溯看起来很像SyntaxError回溯,但它实际上是一个IndentationError。错误消息也非常有用。它告诉您行的缩进级别与其他任何缩进级别不匹配。换句话说,print('done')是缩进2个空格的,但是Python找不到任何其他匹配这种缩进级别的代码行。您可以通过确保代码行符合预期的缩进级别来快速修复此问题。

SyntaxError的另一种类型是TabError,只要有一行包含制表符或空格作为缩进,而文件的其余部分包含制表符或空格,就会看到TabError。这可能会隐藏起来,直到Python指出来!

如果制表符的大小与每个缩进级别中的空格数相同,那么看起来所有的行似乎都在同一级别上。然而,如果一行用空格缩进,另一行用制表符缩进,那么Python会指出这是一个问题:

 1 # indentation.py
 2 def foo():
 3     for i in range(10):
 4         print(i)
 5     print('done')
 6
 7 foo()

在这里,第5行是用制表符缩进的,而不是用4个空格。根据您的系统设置,这个代码块在您看来可能是完美的,也可能是完全错误的。

但是,Python会立即注意到这个问题。但在你运行代码,看看Python会告诉你什么是错误的之前,它可能会对你有帮助,看看在不同的标签宽度设置下的代码是什么样子的一个例子:

$ tabs 4 # Sets the shell tab width to 4 spaces
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5       print('done')
     6   
     7   foo()

$ tabs 8 # Sets the shell tab width to 8 spaces (standard)
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5           print('done')
     6   
     7   foo()

$ tabs 3 # Sets the shell tab width to 3 spaces
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5      print('done')
     6   
     7   foo()

请注意上面三个示例之间的显示差异。大多数代码为每个缩进级别使用4个空格,但是第5行在所有3个示例中都使用单个选项卡。标签宽度的变化,基于标签宽度的设置:

  • 如果制表符宽度为4,那么print语句看起来就像是在for循环之外。控制台将在循环结束时打印“done”。
  • 如果制表符宽度是8,这是很多系统的标准,那么print语句看起来就像是在for循环中。控制台会在每个数字之后打印“done”。
  • 如果制表符宽度为3,那么print语句看起来就不合适。在本例中,第5行与任何缩进级别不匹配。

当你运行代码,你会得到以下错误和回溯:

$ python indentation.py
  File "indentation.py", line 5
    print('done')
                ^
TabError: inconsistent use of tabs and spaces in indentation

请注意TabError而不是通常的SyntaxError。Python指出问题所在,并给出有用的错误消息。它清楚地告诉您,在同一个文件中,制表符和空格用于缩进。

解决这个问题的方法是让同一Python代码文件中的所有行都使用制表符或空格,而不是同时使用制表符和空格。对于上面的代码块,修复方法是删除选项卡并用4个空格替换它,这将在For循环完成后打印“done”。

06

定义和调用函数

在定义或调用函数时,可能会遇到Python中无效的语法。例如,如果在函数定义的末尾使用分号而不是冒号,就会看到SyntaxError:

>>>

>>> def fun();
  File "<stdin>", line 1
    def fun();
             ^
SyntaxError: invalid syntax

这里的回溯非常有用,插入符号直接指向问题字符。您可以通过将分号替换为冒号来清除Python中的这种无效语法。

此外,函数定义和函数调用中的关键字参数的顺序必须正确。关键字参数总是跟在位置参数之后。如果不使用此顺序,将导致SyntaxError:

>>>

>>> def fun(a, b):
...     print(a, b)
...
>>> fun(a=1, 2)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

这里,同样,错误消息非常有助于准确地告诉您这行代码的错误之处。

07

Python版本问题

有时候,在一个Python版本中工作得很好的代码会在一个新版本中中断。这是由于语言语法的官方变化。这方面最著名的例子是print语句,它从python2中的一个关键字变成了python3中的一个内置函数:

>>>

>>> # Valid Python 2 syntax that fails in Python 3
>>> print 'hello'
  File "<stdin>", line 1
    print 'hello'
                ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello')?

这是SyntaxError提供的错误消息所展示的示例之一!它不仅告诉您在print调用中缺少圆括号,而且还提供了正确的代码来帮助您修复语句。

您可能会遇到的另一个问题是,当您阅读或学习在较新版本的Python中有效的语法,但在您正在编写的版本中无效的语法时。f-string语法就是一个例子,在3.6之前的Python版本中是不存在的:

>>>

>>> # Any version of python before 3.6 including 2.7
>>> w ='world'
>>> print(f'hello, {w}')
  File "<stdin>", line 1
    print(f'hello, {w}')
                      ^
SyntaxError: invalid syntax

在3.6之前的Python版本中,解释器对f-string语法一无所知,只会提供一个通用的“无效语法”消息。在本例中,问题是代码看起来非常好,但是它是在较老版本的Python中运行的。如果有疑问,请再次检查正在运行的Python版本!

Python语法在不断发展,Python 3.8中引入了一些很酷的新特性:

  1. Walrus操作符(赋值表达式)
  2. 用于调试的F-string语法
  3. Positional-only参数

如果您想尝试这些新特性,那么您需要确保您是在Python 3.8环境中工作。否则,您将得到一个SyntaxError。

Python 3.8还提供了新的SyntaxWarning。在语法有效但看起来仍然可疑的情况下,您将看到此警告。例如,如果列表中的两个元组之间缺少逗号。这在3.8之前的Python版本中是有效的语法,但是代码会产生一个类型错误,因为tuple是不可调用的:

>>>

>>> [(1,2)(2,3)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object is not callable

这个类型错误意味着您不能像调用函数那样调用元组,这是Python解释器认为您正在做的。

在Python 3.8中,这段代码仍然会引发类型错误,但是现在您还会看到一个SyntaxWarning,它指示如何着手修复问题:

>>>

>>> [(1,2)(2,3)]
<stdin>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
Traceback (most recent call last):   
  File "<stdin>", line 1, in <module>    
TypeError: 'tuple' object is not callable

新SyntaxWarning附带的有用信息甚至提供了一个提示(“也许您漏掉了一个逗号?”),以便为您指出正确的方向!

结论

在本教程中,您已经看到了SyntaxError回溯所提供的信息。您还看到了Python中许多常见的无效语法示例,以及这些问题的解决方案。这不仅会加快你的工作流程,而且还会使你成为一个更有帮助的代码审查者!

在编写代码时,请尝试使用能够理解Python语法并提供反馈的IDE。如果您将本教程中的许多无效Python代码示例放到一个良好的IDE中,那么它们应该在您执行代码之前突出显示问题行。

在学习Python时获得一个SyntaxError可能会令人沮丧,但是现在您知道了如何理解回溯消息以及在Python中可能遇到的无效语法形式。下一次出现SyntaxError时,您就可以更好地快速修复这个问题了!

本文分享自微信公众号 - Python与机器学习之路(gh_39aead19f756),作者:Huangwei AI

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-01-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python新手入门指引

    这篇文章是写给想入门Python但是编程基础为零或者很浅的新手同学。不管你是因为兴趣还是工作以及转行需求,都可以参考。我结合自身的学习Python的以及写Pyt...

    HuangWeiAI
  • 年度盘点,30个开创性的Python开源项目-你都用过哪些?

    Python正在蓬勃发展,它的Github页面也是如此。今年对于Python来说是非常好的一年,我们看到了一些非常强大的Python开源项目。今天,我们列出了一...

    HuangWeiAI
  • 想在2020学习Python,这里有8个不可以错过的免费教程和网站

    Python已经激励了很多人去学习编程,并不断地激励着他们。我认识一些人,他们学习Python的原因各不相同,从web开发到机器学习。我看到过一些新人学习Pyt...

    HuangWeiAI
  • Python大牛告诉你一行代码能干什么?神奇

    Python令人着迷的黑魔法。那么我们高效的Python语言一行代码能干什么呢?请先自行脑补! 我们先说说一行代码输出“The Zen of Python”Py...

    企鹅号小编
  • len(x) 击败 x.len(),从内置函数看 Python 的设计思想

    它们预先定义在内置命名空间中,开箱即用,所见即所得。Python 被公认是一种新手友好型的语言,这种说法能够成立,内置函数在其中起到了极关键的作用。

    Python猫
  • Python入门基础教程-准备工作

    目前的Python版本与Python2和Python3,Python2官方通知在2020年将停止更新,所以以下教程选择Python3版本,且选择最新的Pytho...

    知秋小一
  • 1.python简介

    简介 1、python语言介绍 python的创始人:Guido Van Rossum 2、python是一门什么样的语言 编程语言主要从以下几个角度进行分类:...

    zhang_derek
  • Python 基础: Python入门必看之语法基础

    注意点:参数arg、*args、**kwargs三个参数的位置必须是一定的。必须是(arg,*args,**kwargs)这个顺序,否则程序会报错。

    小Gy
  • linux下的python升级

    (2)bzip2-compressed源码:Python-2.5.4.tar.bz2

    py3study
  • 新手学Python, 如何从"入门到入土"变为"从入门到快速上车"?

    导读:今天这篇文章是「大数据DT」内容合伙人王皓关于《Python数据分析与数据化运营》的一篇读书笔记。在大数据公众号后台对话框回复合伙人,免费读书、与50万同...

    华章科技

扫码关注云+社区

领取腾讯云代金券