最近,我一直在阅读一些关于ChatGPT的有趣文章。在一篇文章中,有人发明了一种新的语言,并让ChatGPT运行它。在另一篇文章中,有人在ChatGPT中运行一个虚拟机。后者启发我提出了下面这个问题。
你能在ChatGPT中运行一个交互式Python会话吗?
是的,你可以!而且ChatGPT知道相当多的Python知识!我玩了一下ChatGPT,给它一些不同的提示和指令,然后测试了ChatGPT的极限和对Python语言的理解。我被ChatGPT对Python的理解所震惊了。它理解并给出了正确的代码结果,这些代码包含以下内容:
- 深度解包
- 列表理解
- 迭代器
- 装饰器
- 属性
- 递归
- 巨量的数学运算
- 类
- dunder方法
- 异步编程
ChatGPT还能够编写代码,解决我交给它的任务。
在这篇文章中,我将通过我与ChatGPT的对话摘录来强调ChatGPT所做的一些令人惊奇的事情,以及我所能发现的一些错误。
本节将包含我和ChatGPT之间的对话记录。
对话一
马上,ChatGPT对我来说就有点太啰嗦了......。但至少它显示了理解我想要的东西的迹象,考虑到它给出的例子和它说的关于#!和#?的事情。
好了,ChatGPT似乎理解了基本的函数打印,它知道REPL提示(>>)和没有提示的结果之间的区别。
在这里,ChatGPT显示它记住了我们分配给以前的变量的值,并且能够使用这些值!
ChatGPT显示它了解Python REPL,因为多行块(如函数定义)以>>>前缀开始,但随后的行得到前缀....。
更酷的是,我们可以使用我们刚刚定义的函数,在一个列表理解中使用它,用“#?”来要求对方解释正在发生的事情。
ChatGPT理解了列表和递归函数。它给出了正确的结果,解释了它,它甚至给了我们与所示的列表理解等价的for循环。难道ChatGPT会让我的列表变得毫无用处吗!?
在这一点上,我想知道我们运行的是什么Python版本。
所以,似乎我们正在运行Python 3.10。接下来的解释是正确的,但我没有要求它...
接下来的几个互动将显示我提醒ChatGPT的失败尝试,并试图强迫它以这种方式行事。
这是我试图检查ChatGPT是否会检测到NameError,或者它是否会 "解释 "我的意图,也就是打印字符串。ChatGPT做对了,但它一直在做不请自来的解释。
在这一点上,我放弃了这次对话,因为我无法让ChatGPT停止在我没有要求的情况下做出解释。
我重新启动了对话,并尝试了新的例子。
对话二
让我们更上一层楼,从标准库中导入一个非简单的工具,一个有两个循环变量的循环,并使用函数print
的一个不太常见的参数。
ChatGPT成功地理解了我们正在计算的内容。遗憾的是,它并没有给出正确的结果。
在这里,ChatGPT对之前的错误表示道歉...但也做了同样的事情,在没有被要求时解释代码。然而,它的解释使用了完美的自然语言来描述结果。唯一的问题是,这个结果是错误的。
- 它应该从7开始;而且
- 它应该上升到21。
在这一点上,我想知道部分困难是否来自于我要求将所有的数字打印在同一行,所以我试图在每次调用打印时摆脱end=", "
。
ChatGPT得到的是,我们仍然在做一件和以前类似的事情。它只是给出了错误的结果,因为这一次的结果应该从21开始,一直到37。
对话三
我试着让它变得更简单,删除了关于#?
在这里,ChatGPT能够猜到我想导入什么模块,它甚至还为我打印了版本信息。奇怪的是,这次我们似乎是在 Python 3.9 中运行......。所以,这让我想知道:我能不能导入itertools.pairwise?我不应该这样做,因为itertools.pairwise是在Python 3.10中才引入的。
看来ChatGPT并不那么聪明!至少,让我再试一下配对的循环。
终于来了!这就是正确的结果!
当我得到这个输出时,我差点从椅子上摔下来。请注意,itertools.tee
并不是一个简单的工具,ChatGPT知道如何使用它来实现triplewise,这是pairwise的一个概括。然后,它成功地用它来计算第一个三倍数的总和,这次的结果是完全正确的!
我又给了它一个指令,它完成了这个指令。它没有实现可能的最佳(递归)版本的fib,但至少实现是正确的。
ChatGPT知道Python有一个递归限制吗?
ChatGPT知道Python有递归限制!酷!我没有让ChatGPT解释代码,但它却解释了。我没有告诉ChatGPT要解释代码,但它却解释了。在这一点上,我开始怀疑它与异常有关:每当我的代码出现错误时,ChatGPT都会解释发生了什么。有趣的是,它提出了fib的另一种实现方式,通过使用循环而不是递归来解决递归限制。然后,它继续介绍了很可能是 fib(1050)的结果,但它不是。
那个巨大的数字可能是fib(1050),因为它看起来很可信。但它与正确的结果相差甚远,它以12233开头......并且有大约一半的数字。
ChatGPT理解dunder方法!它知道__init__是用来初始化对象的,它知道__add__是用来把对象加在一起的!
在这种互动中,ChatGPT正确地看到我们应该提出一个错误,但它给出了错误的错误。正确的错误应该是AttributeError
。
现在,我试着告诉ChatGPT不要解释代码,它只是决定创建一个随机的代码。
这时,我的下一个请求超时了,所以我不得不开始一个新的对话。
对话四
终于来了!ChatGPT没有写解释,甚至在出现异常后也没有写解释!
注意 ChatGPT 明白在 Python REPL 中我不能在类定义的方法之间留空行,否则 REPL 会认为我已经完成了对该类的定义。
ChatGPT了解房产的运作方式!
ChatGPT是否了解装饰器?
正确!
它是否知道装饰函数的名称被包装函数所覆盖?
正确!
它知道装饰过的函数有一个奇怪的表示吗?
的确如此!这正是add在你自己的Python REPL中的模样!
ChatGPT甚至还能理解异步代码!三个标签A、B、C的打印顺序是正确的
看起来我们正在连胜,让我们看看ChatGPT是否能正确处理大数字。
我检查了一下,这个结果是正确的!然而,你怎么知道ChatGPT是根据它自己的斐波那契实现来计算的,还是它只是理解斐波那契计算斐波那契数,同时,不知为何知道那个巨大的数字是第1050个斐波那契数?
为了尝试解决这种不确定性,我以一种稍显晦涩的方式重新实现了fibonacci。
对话五
这段对话显示了一个更短更简单的提示,ChatGPT对此的反应很好。
这里有一段低效的代码,用来生成一堆素数。
ChatGPT明白我们在生成素数,并生成了一堆素数!它从上面的神秘单行字中明白了这一点。而且它从上面显示的神秘的单行字中理解了这一点!这是非常令人印象深刻的。然而,有两个问题。
- 它跳过了283号,这个数字应该在列表中,但却没有;以及
- 列表停止得太早,因为它应该一直到59029。
然后,我又超时了......不管怎么说,我已经没有想法去测试ChatGPT的东西了。我只想到了一个。
对话六
这表明ChatGPT了解星形赋值和海象运算符!这一点令人印象深刻。相当令人印象深刻!