声振论坛

 找回密码
 我要加入

QQ登录

只需一步,快速开始

查看: 3878|回复: 1

[Python] 由两个看似等效的main函数说开去

[复制链接]
发表于 2011-1-10 16:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?我要加入

x
我们知道,在一个python脚本文件(.py)中,要指定程序入口点的话,通常由如下的判断开始:
  1. if __name__ == '__main__':
复制代码
而不是在C/C++中的:
  1. main(){}
复制代码

也不是C#/JAVA的:
  1. class SomeClass{      static int main(){}}
复制代码

这样,在Python中的main函数的模拟通常有两种方式。要不是今天遇到的情况,我甚至没有意识到,这两种情况实际上是很不一样的

方式(一),人为构造main()函数:
  1. def main():
  2.     a = 1;
  3.     b = 3;
  4.     print (a,b)

  5. if __name__ == '__main__':
  6.     main();
复制代码

方式(二),直接在条件分支后写代码:
  1. if __name__ == '__main__':
  2.     a = 1;
  3.     b = 3;
  4.     print (a,b)
复制代码


那么,这两种方式,有什么不一样呢?对我而言,按C/C++/C#的语法,语句块中声明的变量,其作用域只在语句块的内部,例如下面的C#的代码:
  1. if( _name_.compareto("__main___") == 0){    int a = 1;    int b = 3;    SomeFunction();}
复制代码

显然,变量a和b是一个局部变量,其作用域不可能超出两个大括号的范围,在大括号的范围之外,在SomeFunction()的内部,都是不可见的。

我们再来看按照第二种python中的程序入口点写法,写出来的某代码:
  1. def SomeFunction():
  2.     print (a,b)
  3.    
  4. if __name__ == '__main__':
  5.     a = 1;
  6.     b = 3;
  7.     SomeFunction();
复制代码
程序仍然输出了  (1,3)  ,这多少有些让我吃惊,因为按照上述的C/C++/C#思维,是不可能发生这样的事情的,即存在于语句块内部的局部变量,在语句块内调用的函数中居然可见。那么只有一种可能,即a,b实际上被声明为了全局变量,作为对比,如果按照第一种python程序入口点的写法,写出来的代码为:

  1. def SomeFunction():
  2.     print (a,b)
  3.    
  4. def main():
  5.     a = 1;
  6.     b = 3;
  7.     SomeFunction();
  8.    
  9. if __name__ == '__main__':
  10.     main();
复制代码
运行时报错:
Traceback (most recent call last):
  File "D:/My Documents/Python/learning/para.py", line 10, in <module>
    main();
  File "D:/My Documents/Python/learning/para.py", line 7, in main
    SomeFunction();
  File "D:/My Documents/Python/learning/para.py", line 2, in SomeFunction
    print (a,b)
NameError: global name 'a' is not defined


这不得不让我们反思,为什么在C/C++/C#中,为什么要限制语句块中变量的作用域?实际上,考察下列代码,就明白了:
  1. # -*- coding: cp936 -*-
  2. def SomeFunction(a,b):
  3.     print (a,b)
  4.    
  5. def main():
  6.     c = int(raw_input(u'输入一个整数:'));
  7.     if c == 1:
  8.         a = 1;
  9.         b = 3;
  10.     SomeFunction(a,b);
  11.    
  12. if __name__ == '__main__':
  13.     main();
复制代码

按如下两种方式输入,程序的输出是:

>>> ================================ RESTART ================================
>>>
输入一个整数:1
(1, 3)
>>> ================================ RESTART ================================
>>>
输入一个整数:2

Traceback (most recent call last):
  File "D:/My Documents/Python/learning/para.py", line 13, in <module>
    main();
  File "D:/My Documents/Python/learning/para.py", line 10, in main
    SomeFunction(a,b);
UnboundLocalError: local variable 'a' referenced before assignment
>>>

在某些情形下(输入整数为c=2时),变量(a和b)错过了创建的代码,而后续的代码却需要使用这些可能错过初始化的变量,程序在运行期报错

作为一个非常喜欢C/C++/C#的程序爱好者,我认为程序语言的设计,程序员对算法的编码,都应当尽量减小运行期错误,尽量使用严格的语法、优良的设计,将程序的错误暴露在编译期。这里有一个例子,为了克服C/C++/C#语言中的赋值(=)和相等(==)的混淆,甚至建议在条件判断中采用:
  1. if (3 == a){}
复制代码
这样,当代码被误写为:
  1. if(3 = a){}
复制代码
程序会在编译器报错,避免了程序在运行时的出现奇怪错误的一种可能性。

_________________________
这就是我想说明的问题:

1)在python中,由于语句块中的变量不再被限制,导致了第二种程序入口点代码的写法无意中声明了全局变量,而对于C/C++/C#程序员转型而来的Python程序员,可能没有意识到这些全局变量的存在

2)在python中,由于语句块中的变量不再被限制,导致了由变量作用域带来的运行期问题,会延迟程序BUG的发现时机,实际上是不利于团队开发和大型程序设计的

_________________________
一家之言,欢迎大家批评!
回复
分享到:

使用道具 举报

发表于 2013-12-14 14:40 | 显示全部楼层
两种不同的作用域管理方式吧,各有优势。
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

QQ|小黑屋|Archiver|手机版|联系我们|声振论坛

GMT+8, 2024-12-28 12:41 , Processed in 0.056216 second(s), 17 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表