【问题标题】:Pass a variable to certain if statements (shared scope)将变量传递给某些 if 语句(共享范围)
【发布时间】:2017-10-18 18:36:06
【问题描述】:

考虑这段代码:

def function(condition):

    if condition == 'condition1':
        print('No problem here')

    if condition == 'condition2':
        test = ['1','2','3','4']
        print(test)

    if condition == 'condition3':
       #doing something else using variable 'test'

是否可以在两个if 语句之间共享静态列表?目前,我有两个工作想法,但都有其局限性

案例一:在函数开头声明静态列表

def function(condition):
    test = ['1','2','3','4']
    if condition == 'condition1':
        print('No problem here')

    if condition == 'condition2':
        print(test)

    if condition == 'condition3':
       #doing something else using variable 'test'

限制:这意味着我将在每次调用function 时创建列表,即使在condition == 'condition1' 时我不需要它

案例2:在两个if语句中声明静态列表

def function(condition):

    if condition == 'condition1':
        print('No problem here')

    if condition == 'condition2':
        test = ['1','2','3','4']
        print(test)

    if condition == 'condition3':
       test = ['1','2','3','4']
       #doing something else using variable 'test'

限制:在这种特殊情况下,它似乎并没有那么糟糕,但如果我的列表有更多嵌套列表的数据,重复它会使代码维护变得更加困难,因为需要进行更改做过不止一次。

也许有一个简单的方法可以解决这个问题,我想太多了,但正如我所说,这是我第一次看到这种情况。

【问题讨论】:

  • 例如,您可以将列表的创建设为一个单独的函数。
  • 哇,是的,我会等着看是否有其他答案出现,但这是一个非常好的观点。不敢相信我没这么看。谢谢!
  • 如果'condition1' 是您唯一不需要该列表的时间,请在该分支中放置一个return,然后再创建该列表。
  • @jasonharper 这是情况的简化版本。我正在考虑更一般的情况。但这是一个非常好的技巧,谢谢你的回答!
  • 您也可以将其作为函数的可选参数。由于它是一个包含数据的列表 - 当翻译遇到def 时会对其进行评估。但这还不够好,只是为了教育目的

标签: python python-3.x if-statement


【解决方案1】:

创建此列表很简单。您在发布上花费的资源可能比使用最佳解决方案所节省的资源要多。 :-) 如果每个函数调用的列表都相同,那么您有几个不错的选择:

(1) 您的案例 1 很好:它易于阅读且易于维护。如果你担心赋值,打开一个优化开关,让解释器意识到这是一个常量赋值。

(2) 自己强制常量状态:将赋值放在函数之前。

test = ['1','2','3','4']

def function(condition):
    if condition ...

编辑

更多信息请查看answer中的时间安排

【讨论】:

  • 即使列表变得更大?我们仍然可以认为多重分配是微不足道的?
  • 是的,一般来说 - 与重复执行的一长串条件相比。
  • @scharette:记住优化规则#1:“不要这样做”。保持代码易于阅读和维护,从长远来看,您几乎总能节省资源。
  • 我同意。但有时一个与另一个一起出现。在某些情况下,优化会带来更高的可读性。我认为我的问题就是一个很好的例子。
  • 当他们走到一起时,一定要这样做!
【解决方案2】:

a lambda expression 的右侧在调用 lambda 之前不会被计算。如果你想避免重新计算列表,你可以

def function(condition):

    getTestArray = lambda: ['1','2','3','4']

    if condition == 'condition1':
        print('No problem here')

    if condition == 'condition2':
        test = getTestArray()
        print(test)

    if condition == 'condition3':
        test = getTestArray()
        #doing something else using variable 'test'

我应该提到,当我们谈到这个主题时,Python 的 lambda 及其 BDFL,Guido,有一段有趣的历史:https://www.quora.com/Why-did-Guido-van-Rossum-want-to-remove-lambda-from-Python-3/answer/Max-Fischer-10

【讨论】:

  • 这很好,我想我会去一个普通的函数调用,但我没有想到 lamdas 表达式。谢谢!
  • 始终使用 def 语句而不是将 lambda 表达式直接绑定到标识符的赋值语句。 - PEP8 样式指南。如果您喜欢 oneliner - 使用 def getTestArray(): return ['1','2','3','4']
  • 是的,这正是我发布答案的原因,我定义了一个函数而不是使用 lambda。我不推荐here
【解决方案3】:

我讨厌条件语句。使用对象和多态。这似乎需要更多的前期工作,但这种模式非常值得学习:

class ProblemAbstract:
    @property
    def test_data(self):
        return [1, 2, 3, 4]

    def process(self):
        raise NotImplementedError("Need to implement 'process'")


class NullProblem(ProblemAbstract):
    def process(self):
        return None


class ProblemType1(ProblemAbstract):
    def process(self):
        return "Do something with: {}".format(self.test_data)


class ProblemType2(ProblemAbstract):
    def process(self):
        return "Do something else with: {}".format(self.test_data)


def function(condition):
    condition_matrix = {
                        'condition1': NullProblem,
                        'condition2': ProblemType1,
                        'condition3': ProblemType2,
                        }
    return condition_matrix[condition]().process()

if __name__ == "__main__":
    print(function('condition1'))
    print(function('condition2'))
    print(function('condition3'))

输出:

None
Do something with: [1, 2, 3, 4]
Do something else with: [1, 2, 3, 4]

【讨论】:

  • 我需要更深入地研究这个,但这似乎是一种很好的做事方式,只是对我正在寻找的案例来说太过分了。不过谢谢!
【解决方案4】:

我最终使用了@wvxvw 评论中的解决方案,并且道具给了他。

我决定创建一个这样的函数

def get_test():
    test = ['1','2','3','4']
    return test

def function(condition):

    if condition == 'condition1':
        print('No problem here')

    if condition == 'condition2':
        test = get_test()
        print(test)

    if condition == 'condition3':
        test= get_test()

其他答案很好,但我并不总是同意选择不优化代码是最好的做事方式。也许我错了,这是个人问题,但在我看来,上面显示的代码是优化的、可读的和可维护的。特别是对于 function 会被调用数千次的情况。

编辑

我做了一些时间来确认答案。这是使用的代码示例,我称之为 Case1

import time

def function(condition):
    test = ['1','2','3','4']
    if condition == 'condition1':
       pass

    if condition == 'condition2':
       pass

    if condition == 'condition3':
       pass

start_time = time.time()
num_iterations = 10000
for i in range(num_iterations):
    function('condition1')
    function('condition2')
    function('condition3')

print("Case1 for %d iterations" %(num_iterations))    
print("--- %s seconds ---" % (time.time() - start_time))

我对 case2 遵循相同的模式,这与我的问题中的 case2 相关,case3 代表我的答案中使用的逻辑。如您所见,只有创建列表会影响测试时间。

结果

Case1 for 10000 iterations
--- 0.01559591293334961 seconds ---

Case2 for 10000 iterations
--- 0.015594244003295898 seconds ---

Case3 for 10000 iterations
--- 0.015636682510375977 seconds ---

Case1 for 1000000 iterations
--- 1.1179990768432617 seconds ---

Case2 for 1000000 iterations
--- 0.9396021366119385 seconds ---

Case3 for 1000000 iterations
--- 1.0606272220611572 seconds ---

总结

我们可以得出结论,所有实现效率的方法都几乎相同。尽管对于纯粹的性能 Case2 似乎是最好的(当你考虑它时这是逻辑)。不过,我认为我们应该参考这个answer

【讨论】:

  • 你应该做一些计时,看看你的新解决方案是否比案例 1 更快或更慢。我想你可能会感到惊讶。
【解决方案5】:

类似于@RobertB 的答案,但使用函数式编程:

from functools import partial

def condition1():
  print('Hello first case')

def condition2(test):
  print('Hello second case. Test var is: {0}'.format(test))

def condition3(test):
  print('Hello thrid case. Test var is: {0}'.format(test))

def function(condition):

  test = []

  if condition in ('condition2', 'condition3'):
    test = ['1','2','3','4']

  conditions = {
    'condition1': condition1,
    'condition2': partial(condition2, test),
    'condition3': partial(condition3, test)
  }

  action = conditions.get(condition, lambda: print(NotImplemented))
  action()

function('condition')
function('condition1')
function('condition2')
function('condition3')

【讨论】:

  • @scharette 我必须承认我的示例远非理想,因为一遍又一遍地重新创建了带有映射的字典,但作为组织条件的示例 - 这已经足够了
猜你喜欢
  • 1970-01-01
  • 2011-08-31
  • 1970-01-01
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 2013-07-31
  • 1970-01-01
相关资源
最近更新 更多