首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何避免使用全局变量?

如何避免使用全局变量?
EN

Stack Overflow用户
提问于 2019-12-13 22:28:39
回答 3查看 16.7K关注 0票数 9

我使用全局变量,但我读到它们不是一个很好的练习或奏鸣曲。我经常使用函数,因此我需要在主函数中使用许多yes/no变量。例如,如何在不使用全局变量的情况下编写以下代码?

代码语言:javascript
复制
def secondary_function():
    global alfa_is_higher_than_12
    global beta_is_higher_than_12

    alfa = 12
    beta = 5

    if alfa > 10:
        alfa_is_higher_than_12 = "yes"
    else:
        alfa_is_higher_than_12 = "no"

    if beta > 10:
        beta_is_higher_than_12 = "yes"
    else:
        beta_is_higher_than_12 = "no"

def main_function():
    global alfa_is_higher_than_12
    global beta_is_higher_than_12

    secondary_function()

    if alfa_is_higher_than_12=="yes":
        print("alfa is higher than 12")
    else:
        print("alfa isn't higher than 12")

    if beta_is_higher_than_12=="yes":
        print("beta is higher than 12")
    else:
        print("beta isn't higher thant 12")

main_function()
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-12-13 22:36:04

人们可能会问,您可能需要这样构造代码的原因是什么,但假设您有自己的原因,您可以只从次要函数返回值:

代码语言:javascript
复制
def secondary_function():

  alfa = 12
  beta = 5

  if alfa > 10:
      alfa_is_higher_than_12 = "yes"
  else:
      alfa_is_higher_than_12 = "no"

  if beta > 10:
      beta_is_higher_than_12 = "yes"
  else:
      beta_is_higher_than_12 = "no"

  return alfa_is_higher_than_12, beta_is_higher_than_12


def main_function():

  alfa_is_higher_than_12, beta_is_higher_than_12 = secondary_function()

  if alfa_is_higher_than_12=="yes":
      print("alfa is higher than 12")
  else:
      print("alfa isn't higher than 12")

  if beta_is_higher_than_12=="yes":
      print("beta is higher than 12")
  else:
      print("beta isn't higher thant 12")
票数 13
EN

Stack Overflow用户

发布于 2019-12-13 22:46:14

术语"毕多尼“不适用于这个主题--在任何编程语言和范例中使用这样的全局语言都是很糟糕的实践,而不是特定于Python的东西。

global关键字是Python提供的工具,可以让您选择退出封装并打破变量的自然作用域。封装意味着您的每个组件都是一个逻辑的、独立的单元,它应该作为一个黑匣子和做一件事工作(注意:这一件事是概念性的,可以由许多可能是非平凡的子步骤组成),而不需要改变全局状态或生成副作用。其原因是模块化:如果程序(和它会的)出现问题,强大的封装使确定失败组件的位置变得非常容易。

封装使代码更易于重构、维护和扩展。如果您需要组件的行为不同,应该很容易删除或调整它,而不需要这些修改导致系统中其他组件更改的多米诺效应。

执行封装的基本工具包括类、函数、参数和return关键字。语言通常提供类似的模块、命名空间和闭包,但最终目标总是限制范围并允许程序员创建松散耦合的抽象。

函数通过参数接收输入,通过返回值生成输出。可以将返回值分配给调用范围中的变量。您可以将参数看作调整函数行为的“旋钮”。在函数内部,变量只是函数所需的临时存储,以生成其一个返回值,然后消失。

理想情况下,函数编写为纯正幂等;也就是说,它们不会修改全局状态,并在多次调用时产生相同的结果。Python对此的要求比其他语言稍低一些,使用某些就地函数(如sortrandom.shuffle )是很自然的。这些异常证明了规则(如果您对排序洗牌有一点了解的话,由于所使用的算法和效率的需要,它们在这些上下文中是有意义的)。

就地算法是不纯的和非幂等的,但是如果它修改的状态仅限于它的参数,并且它的文档和返回值(通常是None)支持这一点,则行为是可预测的和可理解的。

那么,这一切在代码中是什么样子的呢?不幸的是,您的示例似乎是人为的,并且不清楚它的目的/目标,因此没有直接的方法来转换它,从而使封装的优点变得显而易见。

下面列出了这些函数中除了修改全局状态之外的一些问题:

  • 使用"yes""no"字符串文本,而不是True/False布尔值。
  • 函数中的硬编码值,使它们完全是单一用途的(它们也可能是内联的)。
  • 函数中的printing (请参阅上面的副作用注释--如果他们想这样做的话,更愿意返回值并让调用范围打印)。
  • secondary_function这样的通用变量名(我假设这相当于foo/bar的例子,但仍然不能证明它们存在的理由,因此很难将其作为教学示例加以修改)。

但无论如何,这是我的机会:

代码语言:javascript
复制
if __name__ == "__main__":
    alpha = 42
    beta = 6
    print("alpha %s higher than 12" % ("is" if alpha > 12 else "isn't"))
    print("beta %s higher than 12" % ("is" if beta > 12 else "isn't"))

我们可以看到,不需要所有的函数--只要在需要比较的地方编写alpha > 12,并在需要打印时调用print。函数的一个缺点是它们可以隐藏重要的逻辑,所以如果它们的名称和“契约”(由名称、文档串和参数/返回值定义)不清楚,它们只会混淆函数的客户端(通常是自己)。

为了举例说明,假设您经常调用此格式化程序。然后,有理由进行抽象;调用代码将变得很麻烦,并且会变得重复。您可以将格式化代码移动到助手函数,并将任何要注入模板的动态数据传递到模板中:

代码语言:javascript
复制
def fmt_higher(name, n, cutoff=12):
    verb = "is" if n > cutoff else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))

我们可以更进一步,假装n > cutoff是一个更加复杂的测试,如果将其留在fmt_higher中,那么许多小步骤将违背单一责任。也许在代码的其他地方使用了复杂的测试,并且可以推广到支持这两个用例。

在这种情况下,您仍然可以使用参数和返回值来代替global,并对谓词执行与格式化程序相同的抽象:

代码语言:javascript
复制
def complex_predicate(n, cutoff):
    # pretend this function is much more 
    # complex and/or used in many places...
    return n > cutoff

def fmt_higher(name, n, cutoff=12):
    verb = "is" if complex_predicate(n, cutoff) else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))

只有当有足够的理由进行抽象时(调用代码被阻塞,或者当您多次重复类似的代码块时,才是经典的经验法则)。当你做抽象的时候,做适当地

票数 18
EN

Stack Overflow用户

发布于 2019-12-13 22:37:15

永远不要写“全球”。那么,您肯定没有引入任何全局变量。

还可以将这些值作为参数传递:

代码语言:javascript
复制
def secondary_function():
    alfa = 12
    beta = 5

    if alfa > 10:
        alfa_is_higher_than_12 = "yes"
    else:
        alfa_is_higher_than_12 = "no"

    if beta > 10:
        beta_is_higher_than_12 = "yes"
    else:
        beta_is_higher_than_12 = "no"
    return alfa_is_higher_than_12, beta_is_higher_than_12


def main_function(alfa_is_higher_than_12, beta_is_higher_than_12):
    if alfa_is_higher_than_12=="yes":
        print("alfa is higher than 12")
    else:
        print("alfa isn't higher than 12")

    if beta_is_higher_than_12=="yes":
        print("beta is higher than 12")
    else:
        print("beta isn't higher thant 12")

main_function(*secondary_function())
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59330578

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档