【小思考】Python里面有声明和定义分离这一说么?

第一部分:

探究这个问题,还是因为编程的时候碰到了这个错误:

提示tcplink没有定义,tcplink是我自己写的一个给监听到的tcp连接请求分配新线程的函数,不过是写在了下面,就像这样:

如果是C++里面的话,解决这个问题很简单。在文件开头的时候,加上该函数的声明式就OK,这样不仅方便,还能最大限度的保持美观(雾)。但是问题来了,Python里面好像没有声明和定义这一说呀!

到底有没有呢?这个得要从Python脚本的运行机制来看了。

在C++里面,声明是告诉编译器我的程序里将会有这个符号,编译器将声明内容进行记录,在定义处记录入口,分配内存。换言之,由于C++是编译型语言,这就可以对完整的程序进行扫描,进行跨文本域的联系。

然而,Python却不可以,Python是解释型语言,虽然我们自己写的脚本是一个完整文件,但是在给Python解释器执行的时候,依然相当于是把脚本文件里的内容一行一行输入进解释器并执行。这就造成了如果执行的当前语句要调用tcplink,解释器立马会在之前输入的内容中寻找tcplink的定义并执行,如果无法执行则报错。因为有这个机制,直接就导致了不能像C/C++那样,先放个声明式在前面,在把定义放到其他地方。

第二部分:

有些人可能会问,拉倒吧,我编程的时候这样写,funcb在funcc前面,funcb内将执行funcc,为啥运行的时候什么错误都不会报呢?

这就更有的说了,我们先来把这一小段放到Python命令行交互模式下,看结果如何:

对,依然也是什么错误都没发生。那么,根据之前所说,Python解释器是进来一行解释一行,如果无法解释就会立马报错,为什么这里解释器读入了funcc,用户也没有进行funcc的定义,解释器却没有报错呢?

其实,“Python解释器是进来一行解释一行” 这种说法其实还不太严谨。细心的读者能够发现,当在Python解释器输入def funcb():并回车的时候,>>>变成了...,只有在funcb用户定义完成后并确认,才又会回到>>>。一般情况下,用户是输入一行回车,>>>不发生改变,并输出应该有的结果。所以这说明了什么呢?两点问题:

1.在定义funcb()的时候,用户的回车没有让输入的语句执行。

2.定义完成funcb()向解释器发送回车确认的时候,解释器也没有执行之前定义内的内容。(因为如果执行了,一定会报错,就像下面这样)

新的问题又出现了,所以之前解释器到底执行了什么?答案就是:执行了“定义funcb()”这一个语句。这样,第二部分开头的那个问题,我想大家心里应该有答案了。把第二部分开头的那段程序执行过程画个图来理解,就像这样:

简而言之,如果当前只是执行了“定义XXX”的语句,解释器并不关心你具体定义的内容,此时进来的内容,解释器暂不执行。所以由于之前的funcc()是funcb()内定义的内容,自然不执行,也就无关乎是否此时存在funcc()。但!如果我此时调用funcb,解释器就会转而执行funcb内的具体内容,此时如果funcc()还没有被定义,一定会报not defined的错误!咱们来验证一下:

看来,说的不错。而第二部分开头的代码,在funcc实际被执行的时候,已经获得了完整的定义,故就不会报not defined的错误拉~

第三部分:

那么,有没有什么方法,能够让我的Python程序看起来更加整洁美观——不让所谓的“主程序”文件内函数太多而显得杂乱呢?

其实,import是个挺不错的方法,稍微熟悉Python的人都明白,import可以引用其他地方的py等模块,还可以用from module import function的形式,单独引入指定模块内的指定函数、类。

甚至!!

对于一个从C++过来的人,真是傻了。Python的import相当于“把import的东西原封不动塞进import处一整坨”,所以由于是在函数定义内import的,所以import的东西只有在该函数内才可使用~然而C++/C的单独#include预处理指令则是做不到的。

等等。是不是错过了什么重要的东西……

是的,如果import直接导入本文件,是否是可以的呢?如果可以的话,那岂不是之前的例子中,在之前加上:

from 本文件 import funca/b/c,就可以实现类似C++函数声明的作用了?万一成功了,那岂不是……真香?

我们来试试:

看来,真香失败。那么,为什么这种方法不行呢?我们来回顾一下第二部分中部那个我自己画的流程图,由于Python解释器是进来一句执行一句,所以这里执行的内容是:导入daliywork中的funcb。执行这一句的时候,funcb没有定义,故导入失败。

第四部分:

最后一个问题,如果import整个文件自己本身,可不可以实现这种结果呢?(就和只执行定义XXX时解释器不会探究具体定义的内容一样,这种只执行导入整个文件的操作,解释器是否会关心整个文件内的具体内容呢?)

我们再来回顾一下第三部分内关于import一个很直观的解释:

好了,有了这个解释,我觉得大部分人心里已经有答案了。测试代码如下,我们直接执行来看一下结果:

异常栈首先提示funca没有定义,指向daliywork第六行,但这个错误又是因为daliywork的第三行import导致的。这是因为import整个文件后,相当于把除了import这句以外的部分,替换到了import本身的地方,然后执行这些代码,这时候,在引入的部分内,执行到funca,发现还是没有进行定义,这时候再报出funca没有进行定义的错误。需要注意,错误内报了funca没有经过定义,并不是报的执行文件中的funca没有定义(因为此时在源文件line3 import这一句就已经抛出异常了,程序已经停在这里了!),而是import的daliywork里面的第六行出现的错误。这一点十分重要,可以用以下的图解进行解释(PS:画图真好用):

虽然引入的内容里,包括了所有的定义内容,但是由于引入的文件也会发生执行,所以依然无法实现我们想要的效果……

看来,由于Python特殊的解释执行机制,导致了没什么方法可以只把函数的声明提前。以后写代码的时候,还是乖乖要么把定义的函数都放到其他文件通过import module方式导入,通过module.function()形式进行调用;要么乖乖放在要执行该函数的代码的前面吧……

无题

声明定义要分离,Python解释行不行?

千变万化难模拟,绕了一圈空叹息。

原文地址:https://www.cnblogs.com/sbhyc/p/9289199.html

时间: 2024-11-06 07:48:15

【小思考】Python里面有声明和定义分离这一说么?的相关文章

结构体的声明与定义分离

最近看到一种比较新颖的写法 -- 结构体在头文件中声明, 源文件中定义 A.h typedef struct Context Context; A.cpp #include "stdafx.h" #include "A.h" struct Context { int param; char *str; }; 原以为这样应该会报错, 因为头文件中的 "struct Context" 应该是找不到的, 但amazing, 竟然能顺利编译过, 由此让我

C++模板编程:如何使非通用的模板函数实现声明和定义分离

我们在编写C++类库时,为了隐藏实现,往往只能忍痛舍弃模版的强大特性.但如果我们只需要有限的几个类型的模版实现,并且不允许用户传入其他类型时,我们就可以将实例化的代码放在cpp文件中实现了.然而,当我们又需要针对特定类型进行模版偏特化时,由于gcc编译器不允许直接在类中进行偏特化声明,所以正确的写法变得比较复杂.本文通过一个简单的求log2函数的例子,提供了一个在cpp中同时进行偏特化和实例化的一般写法,并且可以使用static_assert在编译期检查参数的实现. 现在假设我们有一个叫做"Ma

【C++注意事项】2 变量声明和定义

不可能将所有的C++程序放到一个文件中咯,因此C++就支持了分离式编译(separate compilation)机制,它允许将程序分为若干个文件,每个文件可被独立编译.这样说明了,当你的程序有很多文件时,修改其中一个文件后不需要将所有文件都重新编译一遍,只需要编译修改过的就好,然后将它们都链接起来. C++是如何支持分离式编译的呢?通过将声明和定义分离开来. 声明(declaration)使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含该名字的声明. 定义(definition)

C++ Prime:变量声明和定义的关系

为了允许把程序拆分为多个逻辑部分来编写,C++语言支持分离式编译机制,允许将程序分割为若干个文件,每个文件可以独立编译. 为了支持分离式编译,C++将声明和定义区分开.声明使得名字为程序所知,一个文件如果想使用别处定义的名字必须包含对那个名字的声明.定义则负责创建与名字关联的实体. 变量声明规定了变量的类型和名字,定义还额外的申请储存空间,也可能会为变量赋一个初值. 想声明一个变量而不是定义它,在变量名之前添加关键字extern,而且不要显示地初始化变量: extern int i; // 声明

为什么C++中声明和定义要分开写

现在开始写项目了,你会发现我们一般都要写一个cpp,对应的还得有一个h文件,那么为什么在C++中我们要这么做? .h就是声明,.cpp就是实现,而所谓分离式实现就是指"声明"和"定义"分别保存在不同的文件中,声明保存在.h文件.定义保存在.cpp文件中. 那么将声明和定义分离有什么意义吗? 首先从非分离式(声明的同时给出定义)看,其内容一般保存在.h文件中,以供多个源文件引用. 但是将定义放在头文件,那么当多个源文件使用#include命令包含此类的头文件便会在链接

变量声明和定义

一.由来 C++支持分离式编译机制,该机制允许将程序分为若干个文件,每个文件可被独立编译. 如果将程序分为多个文件,则需要有在文件间共享代码的方法. 为了支持分离式编译,C++语言将声明和定义区分开来. 二.区别 声明使得名字为程序所熟知,一个文件如果想用别处定义得到名字则必须包含对那个名字的声明.变量声明规定了变量的类型和名字 extern int i ; //声明 i 而非定义 i 定义负责创建与名字关联的实体.定义除了要规定变量的类型和名字,还申请存储空间,也可能会为变量赋一个初始值. i

c++(3)----变量的声明和定义

分离式编译(separate compilation): 允许将程序分割为若干个文件,每个文件可独立编译. 声明:使得名字为程序所知. 定义:负责创建与名字关联的实体. 变量只能被定义一次,但可以被声明多次. 如果要在多个文件中使用同一个变量,就必须将声明和定义分离.此时,变量的定义必须出现在且只能出现在一个文件中,而其他用到该变量的文件必须对其进行声明. extern int i ; // 声明i 而非定义i int j ; // 声明并定义 int c=3; // 声明.定义.初始化 ext

编程语言先声明后定义的思考???

今天写python程序的时候,想将一些次要的方法写在文件末尾(方便浏览重要的方法),但是这个次要的函数是要被重要的函数调用,想到c语言里面的声明,定义,调用这样一种的次序关系.有以下几点: 1.函数与函数之间是不存在定义和调用的次序关系 2.这种关系是c语言编译器所规定的 理解一下编译过程: main函数--->调用函数(这是编译器会往上找,往上找的话,可以知道上面的内容是有限的,可控的.但是如果没用声明,定义,调用的次序关系,编译器往下找的话,结果往往是未知的).

由 '' in 'abc' return True 引发的思考----Python 成员测试操作

最近遇到判断字典中是否存在空字符串'',这个很好判断,直接用:'' in ['a','b','c'],就可以直接判断出来:但是当我对字符串使用 "in" 方法进行判断的时候,发现:'' in 'abc' 仍然会返回True,对于这个问题,之前一直没有注意到过其中的原理,现在去进行探索总结一下: 首先,查看官方文档:https://docs.python.org/2/reference/expressions.html#not-in 文档在5.9.2中:Membership test o