天天看点

对Python和Go的函数传参研究

传参一直是语言中有点纠结的东西。一提到这个,总会有人说,需要区分传值,传递引用,还有传递指针什么的。而且,貌似不同的语言对此也有不同的实现。 我自己也对这个有点搞混了,所以需要实验一下。

我常用的几个语言是,c++,go语言,python这几种。三个语言中,只有c++有引用,而python是没有指针的。参数传递主要就两类,传值和传递引用。

本文只写python和go语言,c++太复杂了,需要专门研究。

试验的主要分为几种类型,分别为:

单一的变量类型,比如int,float这种基本类型。实验中使用int。

复杂点的变量类型,比如数组,string,有的自带map等。试验中使用数组。

复合类型研究,比如class,struct。

貌似python根本就没有指针,引用的概念。所以,方便不少。

但是,这也会带来别的问题,因为问题还是存在,传递参数到函数中,函数内对参数的改变,会不会影响到外面的。

代码:

<code>01</code>

<code>#coding=utf-8</code>

<code>02</code>

<code>03</code>

<code>def</code> <code>play(x):</code>

<code>04</code>

<code>    </code><code>x</code><code>+</code><code>=</code><code>1</code>

<code>05</code>

<code>    </code><code>print</code> <code>"函数内:"</code><code>,x</code>

<code>06</code>

<code>07</code>

<code>x</code><code>=</code><code>1</code>

<code>08</code>

<code>print</code> <code>"初始状态:"</code><code>,x</code>

<code>09</code>

<code>play(x)</code>

<code>10</code>

<code>print</code> <code>"执行play函数后:"</code><code>,x</code>

输出:

<code>1</code>

<code>初始状态: 1</code>

<code>2</code>

<code>函数内: 2</code>

<code>3</code>

<code>执行play函数后: 1</code>

基础变量的传参是复制传参,也就是传值。函数内对变量的操作不会影响外部。

<code>    </code><code>x[</code><code>0</code><code>]</code><code>+</code><code>=</code><code>1</code>

<code>    </code><code>x[</code><code>1</code><code>]</code><code>+</code><code>=</code><code>3</code>

<code>x</code><code>=</code><code>[</code><code>1</code><code>,</code><code>1</code><code>,</code><code>1</code><code>,</code><code>1</code><code>]</code>

<code>初始状态: [1, 1, 1, 1]</code>

<code>函数内: [2, 4, 1, 1]</code>

<code>执行play函数后: [2, 4, 1, 1]</code>

函数内的改变影响了外部。所以这是<b>传递类的引用</b>。不单单是数组,python的dict等类型都是引用传参(它们其实都是类)。所以需要注意。

<code>class</code> <code>mytest:</code>

<code>    </code><code>a</code><code>=</code><code>1</code>

<code>    </code><code>b</code><code>=</code><code>1</code>

<code>    </code><code>def</code> <code>__repr__(</code><code>self</code><code>):</code>

<code>        </code><code>return</code> <code>"a="</code><code>+</code><code>str</code><code>(</code><code>self</code><code>.a)</code><code>+</code><code>",b="</code><code>+</code><code>str</code><code>(</code><code>self</code><code>.b)</code>

<code>    </code><code>x.a</code><code>+</code><code>=</code><code>1</code>

<code>11</code>

<code>    </code><code>x.b</code><code>+</code><code>=</code><code>3</code>

<code>12</code>

<code>13</code>

<code>14</code>

<code>x</code><code>=</code><code>mytest()</code>

<code>15</code>

<code>16</code>

<code>17</code>

<code>18</code>

<code>初始状态: a=1,b=1</code>

<code>函数内: a=2,b=4</code>

<code>执行play函数后: a=2,b=4</code>

这里,对象被传递到函数中,函数内对实例的操作影响到了外面。所以,这是传递对象的引用。

<code>package main</code>

<code>import </code><code>"fmt"</code>

<code>func add(x </code><code>int</code><code>) {</code>

<code>     </code><code>x++</code>

<code>     </code><code>fmt.println(</code><code>"函数内的x:"</code><code>,x)</code>

<code>}</code>

<code>func main() {</code>

<code>    </code><code>x:=1</code>

<code>    </code><code>fmt.println(</code><code>"初始的x:"</code><code>,x)</code>

<code>    </code><code>add(x)</code>

<code>    </code><code>fmt.println(</code><code>"函数执行后的x: "</code><code>,x)</code>

<code>初始的x: 1</code>

<code>函数内的x: 2</code>

<code>函数执行后的x:  1</code>

看的出来,这是传值,函数内对x的操作并没有影响到外部的x。很明显,调用add函数时,函数copy了一份x。这和python的一样。

<code>func add(ptr *</code><code>int</code><code>) {</code>

<code>    </code><code>fmt.println(</code><code>"------函数内------"</code><code>)</code>

<code>     </code><code>*ptr++</code>

<code>     </code><code>fmt.println(</code><code>"ptr指向的值:"</code><code>,*ptr)</code>

<code>     </code><code>fmt.println(</code><code>"ptr指向的地址:"</code><code>,ptr)</code>

<code>    </code><code>var ptr *</code><code>int</code><code>=&amp;x</code>

<code>    </code><code>fmt.println(</code><code>"ptr指针指向的值:"</code><code>,*ptr)</code>

<code>    </code><code>fmt.println(</code><code>"ptr指向的地址:"</code><code>,ptr)</code>

<code>    </code><code>add(ptr)</code>

<code>    </code><code>fmt.println(</code><code>"------函数执行后-----------"</code><code>)</code>

<code>19</code>

<code>    </code><code>fmt.println(</code><code>"ptr指针的值:"</code><code>,*ptr)</code>

<code>20</code>

修改了原来的代码,在主函数声明了一个ptr指针,指向x。然后把指针传递进add函数。

<code>ptr指针指向的值: 1</code>

<code>ptr指向的地址: 0xc208000150</code>

<code>4</code>

<code>------函数内------</code>

<code>5</code>

<code>ptr指向的值: 2</code>

<code>6</code>

<code>7</code>

<code>------函数执行后-----------</code>

<code>8</code>

<code>函数执行后的x:  2</code>

<code>9</code>

<code>ptr指针的值: 2</code>

执行后,外面的x也变成了2.

可以看出,add函数的修改,影响了外部的x。这也是传值,但是,传递的值是一个地址。

<code>func add(array []</code><code>int</code><code>) {</code>

<code>    </code><code>array[0]+=1</code>

<code>    </code><code>array[1]+=2</code>

<code>    </code><code>fmt.println(</code><code>"函数内的数组:"</code><code>,array)</code>

<code>    </code><code>array:=[]</code><code>int</code><code>{1,1,1,1}</code>

<code>    </code><code>fmt.println(</code><code>"-------初始状态------"</code><code>)</code>

<code>    </code><code>fmt.println(</code><code>"初始的数组:"</code><code>,array)</code>

<code>    </code><code>add(array)</code>

<code>    </code><code>fmt.println(</code><code>"函数执行后的数组:"</code><code>,array)</code>

<code>-------初始状态------</code>

<code>初始的数组: [1 1 1 1]</code>

<code>函数内的数组: [2 3 1 1]</code>

<code>函数执行后的数组: [2 3 1 1]</code>

传递数组和传递指针有着类似的效果,在函数内改变了数组内的值,外面的数组值也改了。这个和c类语言类似。

<code>import </code><code>"strconv"</code>

<code>type test </code><code>struct</code><code>{</code>

<code>    </code><code>a </code><code>int</code>

<code>    </code><code>b </code><code>int</code>

<code>func (</code><code>this</code> <code>*test)str()string{</code>

<code>    </code><code>var tmp string</code>

<code>    </code><code>tmp=</code><code>"a:"</code><code>+strconv.itoa(</code><code>this</code><code>.a)+</code><code>" b:"</code><code>+strconv.itoa(</code><code>this</code><code>.b)</code>

<code>    </code><code>return</code> <code>tmp</code>

<code>func add(test test){</code>

<code>    </code><code>test.a+=1</code>

<code>    </code><code>test.b+=2</code>

<code>    </code><code>fmt.println(</code><code>"函数中的struct:"</code><code>,test.str())</code>

<code>21</code>

<code>    </code><code>test:=test{1,10}</code>

<code>22</code>

<code>23</code>

<code>    </code><code>fmt.println(</code><code>"初始的struct:"</code><code>,test.str())</code>

<code>24</code>

<code>25</code>

<code>    </code><code>add(test)</code>

<code>26</code>

<code>27</code>

<code>    </code><code>fmt.println(</code><code>"函数执行后的struct:"</code><code>,test.str())</code>

<code>28</code>

<code>初始的struct: a:1 b:10</code>

<code>函数中的struct: a:2 b:12</code>

<code>函数执行后的struct: a:1 b:10</code>

被作为参数传入给函数的结构体test,在add函数里对2个值做了加1和加2操作,但是没有影响到外部的变量。这是传值。

从上面的实验来看,无论是python还是go,它们的基础类型在传参时都是复制传参(传值)。对于数组,二者也是一样,类似传递指针,属于传递引用。

但是对于对象,python参数传递类似于指针传递(传对象引用),go语言则是类似于c类语言,属于复制传参。

语言

python

go语言

基础变量传参

传值

数组

传递引用

对象

传递引用(arry,dict属于对象)