首页 > 解决方案 > Python; 为什么传递函数参数不是强制性的

问题描述

在我看来,将要在函数中使用的变量传递给 python 中的函数并不是强制性的。

这段代码:

def functionWithoutArgs():
    print(theList)
    theList.append('asdf')
    print(theList)
    theNewList = theList + ['qwer']
    print(theNewList)
    return theNewList

theList = ['this', 'is', 'a', 'list']
theLastList = functionWithoutArgs()
print(theLastList)

给我这个输出(没有错误或警告):

['this', 'is', 'a', 'list']
['this', 'is', 'a', 'list', 'asdf']
['this', 'is', 'a', 'list', 'asdf', 'qwer']
['this', 'is', 'a', 'list', 'asdf', 'qwer']

我很惊讶没有提出任何例外。这是因为(在我看来)允许函数使用尚未传递给它们的变量会严重混淆该函数与其他代码的交互方式。
据我了解,函数的全部意义在于将程序分解成小部分,这些小部分与其余代码的交互明确定义。

问题
为什么 python 允许在尚未传递给该函数的函数中使用变量?

附加信息:
示例中代码过多的原因是这个线程 Use a Variable in a Function without Passing as an Argument 接受的答案声称仅在被调用函数不修改或重命名变量时才允许使用未传递的变量(至少据我所知),上面的代码是反例。

我知道这个问题是边缘主观或基于意见的,因为它是一个“为什么......”的问题,但我觉得这是非常基本的,因此必须对此达成某种共识。此外,对于许多新的 Python 程序员来说,这将是有用的知识。

标签: pythonarguments

解决方案


完整的答案需要深入解释整个语言的工作原理,这已经记录在案——关于范围和命名空间的官方文​​档可能是这里最好的起点。

长话短说,在 Python 中,一切都是对象——包括函数、类和模块——并且函数、模块和类没有不同的命名空间。IOW,在以下代码中:

FOO_FACTOR = 2

def foo(arg):
    return bar(arg) * FOO_FACTOR

def bar(arg):
    return arg + 3

in foo,bar实际上是一个全局变量,就像FOO_FACTORis 一样。如果不允许函数访问全局范围内的名称,则必须显式传递barand FOO_FACTOR,如果需要特殊声明来访问全局变量,则每次函数使用另一个函数时都必须编写大量样板代码函数,类或模块,至少可以说是非常不切实际的。

允许函数使用尚未传递给它们的变量会严重混淆该函数与其他代码的交互方式。

好吧,重新绑定(甚至只是改变)非本地名称确实会导致很多问题 - wrt/ 可读性(推理代码的能力)、可测试性等,还有 wrt/ 并发性和可重入性,应该避免尽可能。

但是从实际的 POV 来看,您几乎无法避免至少拥有“只读”全局变量(符号常量、其他函数、类、模块等),有时您还需要至少几个确实会改变/重新绑定全局名称的函数(例如考虑应用程序设置) - 这里的重点是这些函数应该只在应用程序启动时调用来定义你的符号常量等。


推荐阅读