代码之家  ›  专栏  ›  技术社区  ›  Alexander Tsepkov

在python函数中使用参数

  •  4
  • Alexander Tsepkov  · 技术社区  · 14 年前

    我知道python中的mutuable和i m mutable参数,也就是说,这是一个奇怪的问题,我遇到了可变参数。简化版本如下:

    def fun1a(tmp):
        tmp.append(3)
        tmp.append(2)
        tmp.append(1)
        return True
    
    def fun1(a):
        b = fun1a(a)
        print a #prints [3,2,1]
        return b
    
    def fun2a():
        tmp = []
        tmp.append(3)
        tmp.append(2)
        tmp.append(1)
        return [True, tmp]
    
    def fun2(a):
        [b, a] = fun2a()
        print a #prints [3,2,1]
        return b
    
    def main():
        a=[]
        if fun1(a):
            print a #prints [3,2,1]
        if fun2(b):
            print b #prints garbage, e.g. (0,1)
    

    如您所见,唯一的区别是fun2指向传入的参数以引用在fun2 a中创建的列表,而fun1只是追加到在main中创建的列表。最后,fun1返回正确的结果,而fun2返回随机垃圾,而不是我期望的结果。这里有什么问题?

    谢谢

    3 回复  |  直到 14 年前
        1
  •  3
  •   jon_darkstar    14 年前

    这不是一个可变/不变的问题,而是一个范围。

    “B”只存在于fun1和fun2体中。它不在主要或全球范围内(至少是有意的)

    --编辑——

    >>> def fun1(b):
    ...     b = b + 1
    ...     return b
    ... 
    >>> def fun2(a):
    ...     b = 1
    ...     return b
    ... 
    >>> fun1(5)
    6
    >>> fun2(b)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    NameError: name 'b' is not defined
    

    (来自我在终端的翻译)

    我猜你的“B”是在别的地方初始化的。在另一个函数中发生的事情对这个没有影响。

    这是我运行您的确切代码:

    >>> main()
    [3, 2, 1]
    [3, 2, 1]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 5, in main
    NameError: global name 'b' is not defined
    >>> b = 'whatever'
    >>> main()
    [3, 2, 1]
    [3, 2, 1]
    [3, 2, 1]
    whatever
    
        2
  •  1
  •   johnsyweb    14 年前

    正如其他人指出的,没有名字' b 在你 main() 功能。

    断言代码行为的更好方法是对其进行单元测试。单元测试在Python中非常容易,并且是一个很好的习惯。几年前,当我第一次开始编写Python时,我和他搭档的那个人坚持要测试所有东西。从那天起,我就一直在使用Python调试器。我离题了…

    考虑:

    import unittest
    
    class Test(unittest.TestCase):
    
        def test_fun1a_populates_tmp(self):
            some_list = []
            fun1a(tmp=some_list)
            self.assertEquals([3, 2, 1], some_list)
    
        def test_fun1a_returns_true(self):
            some_list = []
            ret = fun1a(tmp=some_list)
            self.assertTrue(ret)
    
        def test_fun1_populates_a(self):
            some_list = []
            fun1(a=some_list)
            self.assertEquals([3, 2, 1], some_list)
    
        def test_fun1_returns_true(self):
            some_list = []
            ret = fun1(a=some_list)
            self.assertTrue(ret)
    
        def test_fun2a_populates_returned_list(self):
            ret = fun2a()
            self.assertEquals([True, [3, 2, 1]], ret)
    
        def test_fun2_returns_true(self):
            some_list = []
            ret = fun2(some_list)
            self.assertTrue(ret)
    
        def test_fun2_des_not_populate_passed_list(self):
            some_list = []
            fun2(some_list)
            self.assertEqual(0, len(some_list))
    
    
    if __name__ == '__main__':
        unittest.main()
    

    这些单元测试中的每一个都通过并记录了您的函数的行为(除了打印,如果需要,您还可以为这些测试添加测试)。它们还为您编辑代码提供了一个工具,因为如果您破坏了某个代码,它们应该继续通过或开始失败。

    我没有单元测试 主体() 因为它显然是坏的。

        3
  •  -1
  •   Eric Pauley    14 年前

    问题可能与列表和元组之间的差异有关。在fun2中,不要将括号放在a、b周围。 在fun2a中,返回两个对象的元组,而不是列表。如果您正试图解决这个问题,那么python应该正确地编写变量。 另外,当从未定义b时,您使用参数b调用了fun2。当然,fun2的参数从来没有实际使用过,因为它是在读取之前重写的。

    最后,您的代码应该如下所示:

    def fun1a(tmp):
    tmp.append(3)
    tmp.append(2)
    tmp.append(1)
    return True
    
    def fun1(a):
        b = fun1a(a)
        print a #prints [3,2,1]
        return b
    
    def fun2a():
        tmp = []
        tmp.append(3)
        tmp.append(2)
        tmp.append(1)
        return (True, tmp)
    
    def fun2():
        b, a = fun2a()
        print a #prints [3,2,1]
        return b
    
    def main():
        a=[]
        if fun1(a):
            print a #prints [3,2,1]
        if fun2():
            print b #prints garbage, e.g. (0,1)
    

    应该同时打印[3,2,1]。