|
|
|
|
|
|
M**T 发帖数: 108 | 1 【 以下文字转载自 biojailbreak 俱乐部 】
发信人: MAAT (gogogo), 信区: biojailbreak
标 题: 求教python问题,在线等
发信站: BBS 未名空间站 (Thu Oct 23 23:38:16 2014, 美东)
如何解释一下的输入结果,在modify的方法结束以后,发生了什么,为啥b的指针又给
回到了原来的位置??很明显方法是传递了指针进去,但是为啥方法运行完了就变会原
来了?
class num:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def modify(a, b):
print('the memory address of argu 1nd para before =')
print(a)
print('the memory address of argu 2nd para before =')
print(b)
b = a
b.x = 10000
print('the memory address of argu 1nd para after =')
print(a)
print('the memory address of argu 2nd para after =')
print(b)
if __name__ == "__main__":
e = num(4,5,6)
f = num(7,8,9)
print('object e before modify')
print(e)
print('object f before modify')
print(f)
modify(e, f)
print('object f after modify')
print(f)
print(f.x, f.y, f.z) | a9 发帖数: 21638 | 2 python有指针?
【在 M**T 的大作中提到】 : 【 以下文字转载自 biojailbreak 俱乐部 】 : 发信人: MAAT (gogogo), 信区: biojailbreak : 标 题: 求教python问题,在线等 : 发信站: BBS 未名空间站 (Thu Oct 23 23:38:16 2014, 美东) : 如何解释一下的输入结果,在modify的方法结束以后,发生了什么,为啥b的指针又给 : 回到了原来的位置??很明显方法是传递了指针进去,但是为啥方法运行完了就变会原 : 来了? : class num: : def __init__(self, x, y, z): : self.x = x
| l**********n 发帖数: 8443 | | V*********r 发帖数: 666 | 4 提法的错误太多,就不一一纠正了。只说正确的。
modify是一个函数(不是方法),其参数是a、b两个局部名字。
一个名字是有作用域的,但其所引用的对象是全局的,在堆上,
出了名字的作用域,该名字所引用的对象的引用计数减一。
`b = a`一句的意思,是
1. 名字b原先引用的对象的引用计数减一
2. 让b转而引用a所引用的对象(也就是两个局部名字引用同一对象)
接下来`b.x = 10000`意思是:
让名字b所引用的那个对象的属性x,也就是b.x,引用一个整型对象10000 | M**T 发帖数: 108 | 5 pass by reference,提法有错误,指的是传内存地址进去不是复制然后传进去
【在 a9 的大作中提到】 : python有指针?
| p***o 发帖数: 1252 | 6 你把a和b都当C的指针看就明白了。
【在 M**T 的大作中提到】 : pass by reference,提法有错误,指的是传内存地址进去不是复制然后传进去
| V*********r 发帖数: 666 | 7
你对python的“变量”、“赋值”(“传参”也算是赋值)的理解有偏差。
打个比方,下面的python代码
x = 1
y = x
x = 2.0
print(y) # output is 1
生硬地翻译成C语言,大致等效于
int *t1 = (int *) malloc(sizeof(int));
*t1 = 1;
void *x = t;
void *y = x;
float *t2 = (float *) malloc(sizeof(float));
*t2 = 2.0;
x = t2;
printf("%d", *y);
【在 M**T 的大作中提到】 : pass by reference,提法有错误,指的是传内存地址进去不是复制然后传进去
| M**T 发帖数: 108 | 8 谢谢大牛,尽管没太看懂你的答案,但是用java写了一遍就大概知道怎么一回事情了,
类似的code在java那里就没法通过编译,改了改才行
【在 V*********r 的大作中提到】 : 提法的错误太多,就不一一纠正了。只说正确的。 : modify是一个函数(不是方法),其参数是a、b两个局部名字。 : 一个名字是有作用域的,但其所引用的对象是全局的,在堆上, : 出了名字的作用域,该名字所引用的对象的引用计数减一。 : `b = a`一句的意思,是 : 1. 名字b原先引用的对象的引用计数减一 : 2. 让b转而引用a所引用的对象(也就是两个局部名字引用同一对象) : 接下来`b.x = 10000`意思是: : 让名字b所引用的那个对象的属性x,也就是b.x,引用一个整型对象10000
| M**T 发帖数: 108 | 9 /* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone{
num na, nb, nc, nd, nf;
private class num{
int x, y, z;
public num(int a, int b, int c){
x =a; y = b; z = c;
}
}
public void add_na(int a, int b, int c){
na = new num(a, b, c);
}
public void add_nb(int a, int b, int c){
nb = new num(a, b, c);
}
public void modify(){
na = nb;
nb.x = 1000;
}
public static void main (String[] args) throws java.lang.Exception
{
Ideone root = new Ideone();
root.add_na(1,2,3);
root.add_nb(4,5,6);
root.modify();
System.out.println(root.na.x + ", " + root.na.y + ", " + root.na.z);
System.out.println(root.nb.x + ", " + root.nb.y + ", " + root.nb.z);
}
}
和这段java code相比,na = nb 把nb的reference 给了na之后,na本来的指向的地方
已经可以进垃圾回收站了。na和nb肯定到了同一个位置。为啥python上那个函数(或者
叫方法)运行完了,a和b又回到了原来指向的位置呢? | M**T 发帖数: 108 | 10 大牛一指点,醍醐灌顶啊!这下明白了。
【在 V*********r 的大作中提到】 : : 你对python的“变量”、“赋值”(“传参”也算是赋值)的理解有偏差。 : 打个比方,下面的python代码 : x = 1 : y = x : x = 2.0 : print(y) # output is 1 : 生硬地翻译成C语言,大致等效于 : int *t1 = (int *) malloc(sizeof(int)); : *t1 = 1;
| | | e********3 发帖数: 18578 | 11 传进去的只是b这个reference的value 的copy,在主程序里面b仍然指向那个内存空间
,不会变的。python是pass-by-value,period。
【在 M**T 的大作中提到】 : 大牛一指点,醍醐灌顶啊!这下明白了。
| V*********r 发帖数: 666 | 12
恰恰相反,Python赋值和“传参”,在Python语言层面,都是纯粹地传引用,不是传值;
在CPython实现中,其实是传(二级)指针,只不过指针的概念没有往上暴露给Python。
比如这段python代码,a-->b传参时,传给b的就是a这个符号所指示的那个对象的引用。
def modify(b):
b[1] = 9
a = [0,1]
modify(a)
print(a[1]) # output 9
Python“传参”其实就是赋值,完完全全地等效。上述代码等效于:
a = [0,1]
b = a
b[1] = 9
print(a[1]) # output 9
第一段Python代码的大致等效的C语言代码如下:
#include
void modify(void *b) {
int **c = (int **) b;
(*c)[1] = 9;
}
int main()
{
int *a = malloc(2 * sizeof(int));
a[0] = 0;
a[1] = 1;
modify(&a);
printf("%d", a[1]);
}
第二段Python代码等价于:
int main()
{
int *a = malloc(2 * sizeof(int));
a[0] = 0;
a[1] = 1;
void *b = &a;
int **c = (int **) b;
(*c)[1] = 9;
printf("%d", a[1]);
}
这两段C语言代码主要是为了说明:
1. 所有的Python对象都是在堆上malloc出来的,全局作用域,引用计数gc;
而指向对象的标识符(或者叫名字、符号),比如这里的a、b,有几级namespace,
你可以大致想象他们是在栈上创建的,出了作用域之后其指向对象的引用计数减一。
2. Python标识符是无类型的(尽管其所指示的对象被普遍认为是所谓“强类型”的),
在C层面是void *型(在CPython实现里,准确地说是PyObject **)。
3. 赋值和传参,在Python层面是传引用,在C层面是传指针。
大多数动态语言,比如Ruby,机理也是类似的。
【在 e********3 的大作中提到】 : 传进去的只是b这个reference的value 的copy,在主程序里面b仍然指向那个内存空间 : ,不会变的。python是pass-by-value,period。
| z****e 发帖数: 54598 | 13 而且用ide可以当场就提示你出了什么问题
【在 M**T 的大作中提到】 : 谢谢大牛,尽管没太看懂你的答案,但是用java写了一遍就大概知道怎么一回事情了, : 类似的code在java那里就没法通过编译,改了改才行
| e********3 发帖数: 18578 | 14 跟你说了传的是value of reference, 不是reference of reference, ruby我也测试过
,和Java都是类似的机理。
值;
Python。
用。
【在 V*********r 的大作中提到】 : : 恰恰相反,Python赋值和“传参”,在Python语言层面,都是纯粹地传引用,不是传值; : 在CPython实现中,其实是传(二级)指针,只不过指针的概念没有往上暴露给Python。 : 比如这段python代码,a-->b传参时,传给b的就是a这个符号所指示的那个对象的引用。 : def modify(b): : b[1] = 9 : : a = [0,1] : modify(a) : print(a[1]) # output 9
| y***a 发帖数: 840 | 15 上面几个回帖挺有用。
有人叫pass-by-name, 有人叫pass-by-object-reference.
下面这个文章解释的还不错。
http://robertheaton.com/2014/02/09/pythons-pass-by-object-refer
【在 e********3 的大作中提到】 : 跟你说了传的是value of reference, 不是reference of reference, ruby我也测试过 : ,和Java都是类似的机理。 : : 值; : Python。 : 用。
| e********3 发帖数: 18578 | 16 谢谢,学写了。
【在 y***a 的大作中提到】 : 上面几个回帖挺有用。 : 有人叫pass-by-name, 有人叫pass-by-object-reference. : 下面这个文章解释的还不错。 : http://robertheaton.com/2014/02/09/pythons-pass-by-object-refer
| p***o 发帖数: 1252 | 17 这么罗嗦,直接大大方方的说跟C一样指针按值传递不就完了。
【在 y***a 的大作中提到】 : 上面几个回帖挺有用。 : 有人叫pass-by-name, 有人叫pass-by-object-reference. : 下面这个文章解释的还不错。 : http://robertheaton.com/2014/02/09/pythons-pass-by-object-refer
| a9 发帖数: 21638 | 18 这些新的语言基本都类似吧。
java,c#,python...
【在 p***o 的大作中提到】 : 这么罗嗦,直接大大方方的说跟C一样指针按值传递不就完了。
|
|
|
|
|
|
|