猫史档案馆


【Python硬核知识】为什么写Python时有的方法(函数)名打出来不自动加括号

用户:SenseiMaxBaiSenseiMaxBai查看:7 回复:4 评论:7 创建时间:2024-02-01T13:11:09


在前段时间有位训练师问了我一个问题:为什么他写p.forward()、p.dot()这样的方法时,编辑器总是给他自动打出来一对括号;而p.ht()方法总是不打出这对括号呢?

事实上,在现代的IDE(集成开发环境,例如海龟编辑器)和纯代码编辑器(例如Visual Studio Code)中,基本都支持写出一个方法(函数)名后自动添加括号的功能。如果有的IDE破天荒地不支持,那它就很有可能会被编程人员们嫌弃。下图就是在微软出品的Visual Studio Code中打开Python自动补全括号的方式。center_image

这么说来,海龟编辑器也有自动补括号的功能,但为什么在写p.ht时,海龟就是不肯“好心地”帮这位训练师补全一对括号呢?事实上,当他问出这个问题的时候,很明显把我也问懵了,于是带着他的问题,我打开了turtle库的源代码turtle.py,然后看见了这些代码(使用IDE为Jetbrains PyCharm):

center_image

答案就在2486行的ht = hideturtle中。在学习编程课时,我们称ht是hideturtle的简写,不管我们写p.ht()还是p.hideturtle(),画笔p都会被隐藏;可是,ht虽然和hideturtle功能完全一样,但严格来说,ht并不是一个真正的方法(函数),而是一个变量,它的类型是一个函数指针(function pointer)

在Python中,函数指针实际上是一个方法(函数,function)对象的引用。我们可以使用方法(函数)名来获得方法(函数)对象的引用,然后通过函数对象来调用函数,使用方式和原函数一样。例如:

center_image

可以看到,cal和add中写入(1, 2)产生了一样的运算结果。事实上,cal变量还可以赋值为任何有两个不限类型参数a、b的函数,使用cal都会和它指向的函数产生一样的效果。

说到这里其实我们还没有解释为什么写入ht不会让编辑器自动打出括号。我们需要清楚一个事实,那就是只有确认你输入的某个名字是一个函数时,IDE才会给你添加上这对括号。定义函数用的关键字是def,它定义出来的名字就确定是一个函数,hideturtle就是用def定义出来的;而ht仅仅是一个函数指针,指向hideturtle,它的本质还是一个变量,而不是一个函数。因此,写出p.ht时,IDE不会自动加上括号,具体原因可以自己思考一下(提示:变量可以用=赋值号赋值为别的数据)。

center_image

似乎晕晕乎乎明白了这个道理,这位机灵的训练师又问,为什么在写for循环时,range方法也不加括号呀?难道range也是一个变量吗?于是我点开了range的定义所在的代码文件builtins.py,在4315行看见了range的真实面目:

center_image

range前面的定义关键字是class,它告诉我们,range不是一个函数,而是一个数据类型,或者叫类(class)。其实,整数(int)、字符串(str)都是类,它们都是用class定义出来的。而在range后面的括号,表示我们正在使用的是range类提供的构造器(constructor)!它会给我们构造出一个从0开始、一共n(stop)个数的range类型变量。这个构造器也是一种函数,但是它和我们普通的函数不一样,它没有名字,使用它的方式是类名+参数列表。因此,range不是一个函数,写range也不会自动补上一对括号,具体原因可以自己思考一下(提示:类有一种函数叫静态函数,可以自行了解,本文不再涉及)。

center_image

相信能看到这里你也稍微有点晕了,简单省流概括一下就是:IDE只会在方法(函数)名后面自动添加,而ht、range都不是方法,所以没有自动添加括号的机制。事实上,turtle.Pen()、turtle.done()都不是函数,本不应该自动添加括号的,但海龟编辑器很贴心地在这上面做了优化,因为这两句代码过于常用,所以在你写这两句代码时也会自动添加一对括号。

总而言之,能问出这样的问题,说明这位训练师观察非常仔细,而且也非常愿意反思、探讨,很有潜力;而要想真正理解这背后的原因,仅仅通过本篇硬核知识文章是不够的,还需要很长时间的知识积累和代码实践。各位训练师仍然任重而道远,希望你们可以坚持学习下去,一天天迈向你们的编程大师的目标!


回复

上一页1 页 / 共 1下一页
1111111111111111211111111111111112

哪个训练诗啊

 

点赞0


评论


owugi7s6awaowugi7s6awa

()没啥用,但有知识

点赞1


评论


压潮压潮

好深奥

点赞0


评论


jczzcjczzc

vs的函数指针在类和模块自身内部甚至都是不识别的,和函数、多线程传参一样,调用的似乎事一个内存块,本质还是有C系指针的思想,但是很明显隐去了基础调用,有的搞得我每次还得深拷贝……(赞美全局变量,明人不说暗话

外部调用的时候,可以发现自动补全会显示变量的提示……

事实上,我甚至认为就连function本身也是一个有__call__方法的类

之前还见过一个写C++的转C#不习惯自动垃圾回收的

点赞0


评论