Python:我应该避免在块内部对变量进行初始化吗?

Cha*_*lie 5 python variables scope

问题

我有这样的代码

if condition:
    a = f(x)
else:
    a = g(y)
Run Code Online (Sandbox Code Playgroud)

a块内部的初始化对我来说很糟糕.可以写得更好吗?

我不能使用三元运算符,因为函数和/或参数列表的名称很长.说"长"我的意思是以下表达式

a = f(x) if condition else g(y)
Run Code Online (Sandbox Code Playgroud)

需要超过79(有时甚至大于119)的符号使用实名的代替a,f,g,x,ycondition.使用多个斜杠会使代码变得丑陋和混乱.

我不想a用默认函数初始化其中一个函数的结果,因为这两个函数都很慢,我不能允许这样的开销

a = g(y)
if condition:
    a = f(x)
Run Code Online (Sandbox Code Playgroud)

我可以初始化变量None,但这个解决方案是否已足够?

a = None
if condition:
    a = f(x)
else:
    a = g(y)
Run Code Online (Sandbox Code Playgroud)

让我解释一下我的立场:在C和C++中,块内部的变量都以块作为其范围.在ES6 let中引入了关键字 - 它允许使用与C和C++中的变量相同的范围规则创建变量.使用old var关键字定义的变量具有与Python类似的范围规则.这就是为什么我认为如果我想在这些块之外使用变量,那么变量的初始化应该在块外部进行.

更新

这是一个更复杂的例子

for obj in gen:
    # do something with the `obj`
    if predicate(obj):
        try:
            result = f(obj)
        except Exception as e:
            log(e)
            continue
    else:
        result = g(obj)
    # do something useful with the `result`
else:
    result = h(obj)

display(result)
Run Code Online (Sandbox Code Playgroud)

我浏览了一些生成器的元素gen,处理它们并result在每次迭代时执行一些操作.然后我想用result循环的最后一个做一些事情.

它是pythonic足以不result预先分配虚拟值吗?这不会使代码的可读性降低吗?

初始化if/ else/ for/ etc中的变量是否合适?在Python?

650*_*502 5

Python没有块范围......范围是整个函数,它是完美的pythonic编写

if <condition>:
    a = f()
else:
    a = g()
Run Code Online (Sandbox Code Playgroud)

如果你想用C++编写然后用C++编写C++,不要用Python编写C++ ......这是个坏主意.


Sig*_*lon 4

好的,这里有两点需要澄清,这是 python 的基础。

  1. python 中没有变量声明/初始化。类似的表达式a = f(x)只是将 f 返回的对象命名为的方案a。该名称a稍后可用于命名任何其他对象,无论其类型是什么。看这个答案。

  2. python 中的块可以是模块、类或函数的主体。这些对象内定义/命名的任何内容对于后面的代码都是可见的,直到块结束。循环或 if-else 不是块。因此,在循环外部或 if/else 之前定义的任何名称都将在循环内部可见,反之亦然。看到这个globalnonlocal对象略有不同。python 中没有,let因为这是默认行为。

在您的情况下,唯一关心的是您如何a在代码中进一步使用。f如果您的代码需要or返回的对象类型,g除非出现错误,否则它应该可以正常工作。因为 if 或 else 中至少有一个应该在正常操作中运行,因此a将引用某种对象(如果 if 和 else 中的名称不同,那将是一个问题)。如果您想确保后续代码不会中断,您可以使用 atry-except-else捕获函数生成的任何错误,并except在适当报告/记录错误后为子句中的 a 分配默认值。

因此,总结并直接解决您的问题,为 if-else 语句或循环内的对象分配名称是非常好的做法,前提是:

  1. if 和 else 子句中使用相同的名称,以便保证该名称引用语句末尾的对象。额外的try-except-else错误捕获可以处理函数引发的异常。

  2. 名称不应该太短、通用或不能清楚地表达代码意图的名称ares例如,等等。一个合理的名称将带来更好的可读性,并防止稍后对其他对象意外使用相同的名称,从而丢失原来的。