Redian新闻
>
求教python问题,在线等 (转载)
avatar
求教python问题,在线等 (转载)# Programming - 葵花宝典
M*T
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)
avatar
a9
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

avatar
l*n
3
什么是指针?
avatar
V*r
4
提法的错误太多,就不一一纠正了。只说正确的。
modify是一个函数(不是方法),其参数是a、b两个局部名字。
一个名字是有作用域的,但其所引用的对象是全局的,在堆上,
出了名字的作用域,该名字所引用的对象的引用计数减一。
`b = a`一句的意思,是
1. 名字b原先引用的对象的引用计数减一
2. 让b转而引用a所引用的对象(也就是两个局部名字引用同一对象)
接下来`b.x = 10000`意思是:
让名字b所引用的那个对象的属性x,也就是b.x,引用一个整型对象10000
avatar
M*T
5
pass by reference,提法有错误,指的是传内存地址进去不是复制然后传进去

【在 a9 的大作中提到】
: python有指针?
avatar
p*o
6
你把a和b都当C的指针看就明白了。

【在 M**T 的大作中提到】
: pass by reference,提法有错误,指的是传内存地址进去不是复制然后传进去
avatar
V*r
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,提法有错误,指的是传内存地址进去不是复制然后传进去
avatar
M*T
8
谢谢大牛,尽管没太看懂你的答案,但是用java写了一遍就大概知道怎么一回事情了,
类似的code在java那里就没法通过编译,改了改才行

【在 V*********r 的大作中提到】
: 提法的错误太多,就不一一纠正了。只说正确的。
: modify是一个函数(不是方法),其参数是a、b两个局部名字。
: 一个名字是有作用域的,但其所引用的对象是全局的,在堆上,
: 出了名字的作用域,该名字所引用的对象的引用计数减一。
: `b = a`一句的意思,是
: 1. 名字b原先引用的对象的引用计数减一
: 2. 让b转而引用a所引用的对象(也就是两个局部名字引用同一对象)
: 接下来`b.x = 10000`意思是:
: 让名字b所引用的那个对象的属性x,也就是b.x,引用一个整型对象10000

avatar
M*T
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又回到了原来指向的位置呢?
avatar
M*T
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;

avatar
e*3
11
传进去的只是b这个reference的value 的copy,在主程序里面b仍然指向那个内存空间
,不会变的。python是pass-by-value,period。

【在 M**T 的大作中提到】
: 大牛一指点,醍醐灌顶啊!这下明白了。
avatar
V*r
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。

avatar
z*e
13
而且用ide可以当场就提示你出了什么问题

【在 M**T 的大作中提到】
: 谢谢大牛,尽管没太看懂你的答案,但是用java写了一遍就大概知道怎么一回事情了,
: 类似的code在java那里就没法通过编译,改了改才行

avatar
e*3
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

avatar
y*a
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。
: 用。

avatar
p*o
17
这么罗嗦,直接大大方方的说跟C一样指针按值传递不就完了。

【在 y***a 的大作中提到】
: 上面几个回帖挺有用。
: 有人叫pass-by-name, 有人叫pass-by-object-reference.
: 下面这个文章解释的还不错。
: http://robertheaton.com/2014/02/09/pythons-pass-by-object-refer

avatar
a9
18
这些新的语言基本都类似吧。
java,c#,python...

【在 p***o 的大作中提到】
: 这么罗嗦,直接大大方方的说跟C一样指针按值传递不就完了。
相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。