在Python函数中使用参数

时间:2010-11-14 00:57:33

标签: python

我知道Python中的mutuable和immutable参数,这是哪个,但这是一个奇怪的问题,我遇到了可变参数。简化版如下:

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指向传入的参数以引用在fun2a中创建的列表,而fun1只是附加到main中创建的列表。最后,fun1返回正确的结果,而fun2返回随机垃圾而不是我期望的结果。这有什么问题?

由于

3 个答案:

答案 0 :(得分:3)

这不是作为范围之一的可变/不可变问题。

“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

答案 1 :(得分:1)

正如其他人所指出,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()

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

我没有经过单元测试main(),因为它已经明显坏了。

答案 2 :(得分:-1)

问题可能与列表和元组之间的差异有关。在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]。