简体   繁体   English

在Python函数中使用参数

[英]Using arguments in Python functions

I'm aware of mutuable vs immutable arguments in Python, and which is which, but here is a weird issue I ran into with mutable arguments. 我知道Python中的mutuable和immutable参数,这是哪个,但这是一个奇怪的问题,我遇到了可变参数。 The simplified version is as follows: 简化版如下:

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)

As you can see the only difference is that fun2 points the passed in argument to reference a list created inside fun2a, while fun1 simply appends to the list created in main. 正如您所看到的,唯一的区别是fun2指向传入的参数以引用在fun2a中创建的列表,而fun1只是附加到main中创建的列表。 In the end, fun1 returns the correct result, while fun2 returns random garbage rather than the result I'd expect. 最后,fun1返回正确的结果,而fun2返回随机垃圾而不是我期望的结果。 What's the problem here? 这有什么问题?

Thanks 谢谢

This isn't so much of a mutable/immutable issue as one of scope. 这不是作为范围之一的可变/不可变问题。

"b" exists only in fun1 and fun2 bodies. “b”仅存在于fun1和fun2体中。 It is not present in the main or global scope (at least intentionally) 它不存在于主要或全球范围内(至少是故意的)

--EDIT-- - 编辑 -

>>> 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

(From my interpreter in terminal) (来自我在终端的翻译)

I'm guessing your 'b' was initialized somewhere else. 我猜你的'b'是在其他地方初始化的。 What happened in the other function is of has no effect on this. 在其他功能中发生的事情对此没有影响。

This is me running your exact code: 这是我运行您的确切代码:

>>> 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

As others have pointed out, there is no name ' b ' in your main() function. 正如其他人所指出的, main()函数中没有名称“ b ”。

A better way of asserting how your code is behaving is to unit test it. 断言代码行为方式的更好方法是对其进行单元测试。 Unit-testing is very easy in Python and a great habit to get into. 单元测试在Python中非常容易,并且很容易进入。 When I first started writing Python a few years back the guy I paired with insisted on testing everything. 几年前,当我第一次开始编写Python时,我配对的人坚持要测试一切。 Since that day I have continued and have never had to use the Python debugger as a result! 从那天起,我继续并且从未必须使用Python调试器! I digress... 我离题了......

Consider: 考虑:

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()

Each of these unit tests pass and document how your functions behave (save for the printing, you can add the tests for those if they are needed). 这些单元测试中的每一个都传递并记录了函数的行为方式(除了打印,您可以根据需要添加测试)。 They also provide a harness for when you edit your code, because they should continue to pass or start failing if you break something. 它们还为您编辑代码时提供了线束,因为如果您破坏了某些内容,它们应该继续通过或开始失败。

I haven't unit-tested main() , since it is clearly broken. 我没有经过单元测试的main() ,因为它已经明显坏了。

The problem may be related to the difference between lists and tuples. 问题可能与列表和元组之间的差异有关。 In fun2, don't put brackets around a,b. 在fun2中,不要在a,b周围放括号。 In fun2a, return a tuple of the two objects and not a list. 在fun2a中,返回两个对象的元组而不是列表。 Python should write the varaibles correctly, if that's the problem that you're trying to solve. Python应该正确编写变量,如果那是你想要解决的问题。 Also, you called fun2 with argument b when b was never defined. 此外,当b从未定义时,您使用参数b调用fun2。 Of course, the parameter for fun2 is never actually used, because it is rewritten before it is read. 当然,fun2的参数从未实际使用过,因为它在读取之前会被重写。

In the end, your code should look like this: 最后,您的代码应如下所示:

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)

which should print [3,2,1] both times. 应该打印[3,2,1]两次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM