理解Python中的“def main”和“重载”
我经常看到一些代码里面有
def main(A,B)
some steps
被称为“主函数的重载”,但在我读了一些关于Python的具体内容后,我知道这并不准确,因为:
- Python是一种无损类型语言
- 在Python中,函数或方法根本不知道给定参数的类型,Python也不在乎这个
我也不太确定实例和“静态方法”或“类方法”之间是否真的有区别,可能它们是同一种东西,唯一的不同是使用装饰器的方式,但这可能和我在接触函数式语言之前花了很多时间在C/C++上有关。
更重要的是,在Python中,第一个缩进级别被用作入口点(就像C/C++中的main()),所以我不明白为什么要在一个不同于第一个缩进级别的地方定义一个main。
我对Python关键字的总体理解是,这些关键字有特殊的语义价值,而不是一个真正定义的语法(可能是因为C++不那么“习惯用法”,我也不知道怎么解释这个),它们被用作某种占位符,并且给它们应用的部分赋予特殊的意义。还有一些特殊变量,比如__name__
,它们只是用来存储特殊信息而已。
在我脑海中存储了这么多小信息后,我仍然不明白第一个代码示例的真正含义:
- main()函数有什么特别之处?
- 如果它不是真正的“主函数”,那么定义一个“main”函数有什么意义?
- 如果没有类型,Python是怎么决定调用哪个函数的?
- 解释器读取
__init__.py
文件和其他文件有什么区别吗?
2 个回答
在Python中,main()只是一个函数名。常见的用法是
if __name__ == '__main__':
#do something
它是一个快捷方式,用来判断这个文件里的代码是作为程序运行的,而不是被当作模块导入的。
因为Python是类型自由的,所以社区非常重视约定和最佳实践。这虽然没有编译器那样的可预测性,但能帮助减少混乱。可读性是Python的核心价值观,而像这样的用法提供了有价值的结构。
Python不支持像其他语言那样的函数重载。在一些强类型的语言中,你可能会写多个同名但参数不同的函数:
void DoSomething (int a) {};
void DoSomething (float f) {};
void DoSomething (string s){};
但在Python中没有类似的用法。在大多数情况下,这其实是没必要的:对于数字运算,你并不在乎传入的数字是浮点数、整数还是其他类型——只要它们支持正确的运算符就行。这就是Python的“鸭子类型”理念:如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。因此,Python的函数通常会查看传入参数的函数或运算符,而不是检查它们的类型。
关于实例方法和静态方法: 在Python中,每个实例方法隐式地将拥有的实例作为函数的第一个参数:
class Test(object):
def __init__(self, arg):
self.variable = arg
def example(self):
print self.variable
fred = Test(999) # note: no 'self' passed here
fred.example()
>>> 999
joe = Test(-1)
joe.example()
>>> -1
而类方法则将类类型作为隐式的第一个参数。类方法可以访问类级别的变量,这些变量是在类的作用域中定义的,而不是在实例的作用域中——但它们对特定的实例一无所知。
class TestCls (Test)
CLASS_VARIABLE = "hello"
# other behavior inherited from Test
@classmethod
def class_example(cls):
print cls.CLASS_VARIABLE
barney = TestCls(123)
barney.example()
>>> 123
barney.class_example() # again, no explicit class passed in
>>> 'hello'
静态方法则根本没有隐式参数:
class TestStatic (TestCls):
CLASS_VARIABLE = 'goodbye'
# inherited stuff again
@staticmethod
def static_test():
print "behold, I have no implicit argument"
静态方法和类方法也不需要实例来调用:
wilma = TestStatic(123)
wilma.static_test() # you can call from an instance
>>> behold, I have no implicit argument
# or not:
TestStatic.static_test()
>>> behold, I have no implicit argument
TestStatic.class_example()
>>> goodbye # the method is inherited, but the class variable come from this class
来回答你的问题:
main()
函数
这个函数没有什么特别的地方。你需要自己去调用它,比如这样:
def main():
print "This is main"
if __name__ == "__main__":
main()
为什么要用 main()
使用这个函数的原因是为了把主要的入口代码放在一起,方便管理。例如,如果你在 main()
中创建了一些变量,它们就不会成为全局变量,这样可以避免污染全局命名空间。此外,如果你从其他地方导入这个模块(而不是直接运行它作为脚本),main()
函数就不会被执行。这在你不想在导入时进行一些初始化(比如打印消息),但在作为独立脚本运行时又想执行这些操作时,会很有用。
Python 是如何决定调用哪个函数的
Python 在这方面不支持“重载”。在一个特定的命名空间中,只能有一个同名的函数。如果你再创建一个同名的函数(或者在同一个类中创建同名的方法),那么第一个函数就会被完全覆盖。
__init__.py
这个问题其实和你其他的问题没有直接关系。不过,不,它并不是以不同的方式处理它们。它是在不同的时间处理这些文件(当你导入一个包时,而不是导入包中的一个模块),但里面的代码和其他 Python 文件中的代码一样,都是会被执行的。