• Jingxiao 置顶
    2019-06-17
    关于思考题:
    第一题:
    l2和l3是指向同一个对象,因为两者之间用等号赋值了,l1并不是,l1所指向的[1, 2, 3]是另外一块内存空间,大家可以通过id()这个函数验证

    第二题:
    输出的是{'a': 10, 'b': 20},字典是可变的,传入函数后,函数里的d和外部的d实际上都指向同一个对象
    d[idx] = value语句改变了字典对应key所指向的值
    展开
     1
     21
  • 不瘦到140不改名
    2019-06-14
    针对@小恶魔的问题,回复一下

    python里面一切皆对象, 比如a=1。在java里面是int a = 1,相当于先声明了一个int类型的变量a,然后给这个变量赋值为1。但在python中,是先在内存中申请一份空间,存的值为1,然后再给这块空间贴上一个标签,叫变量a,因此python中变量实际上是一个便利贴,可以贴在任何地方。并且还可以通过值来推断出变量的类型,这一步是由解释器来完成的。所以python虽然不需要显式声明变量,但它其实是强类型语言。
    def func(d):
        d['a'] = 10
        d['b'] = 20
        d = {'a': 1, 'b': 2}


    d = {}
    func(d)
    print(d) # {'a': 10, 'b': 20}

    至于这里为什么会是这个结果,当我们将d传递给func的时候,其实func里面的d和外面的d指向的是同一片内存。相当于一开始d={},存放{}这份空间只有d这一个便利贴,但是func(d)的时候,这份空间又多了一个便利贴。尽管都叫d,但一个是全局变量d,一个是函数的参数d
    当d['a'] = 10和d['b']=20的时候,由于字典是可变类型,所以外面的d也被修改了,此时外面的d和函数里面的d都指向了{'a': 10, 'b': 20}, 但是当d = {'a': 1, 'b': 2}的时候,这是属于赋值。因此python会在内存中再开辟一份空间,空间存放{'a': 1, 'b': 2},然后让函数里面的局部变量d指向它,相当于将原本位于{'a':10,'b':20}上的便利贴撕下来,贴在了另一块空间。但这只是函数里面的d,对外面的d是没有影响的,所以外面的d依旧是{'a': 10, 'b': 20}。
    展开
     7
     39
  • somenzz
    2019-06-14
    第一个比较简单,列表是可变对象,每创建一个列表,都会重新分配内存,因此 l1 和 l2 并不是同一个对象,由于 l3 = l2 表明 l3 指向 l2 的对象。

    第二个 输出的结果应该是 {'a': 10, 'b': 20} ,d = {'a': 1, 'b': 2} 属于重新指向新的对象,并不改变原有的字典对象。
    
     8
  • yshan
    2019-06-16
    首先更正下,需要先定义d={}。
    然后,局部变量与全局变量的区别,函数内定义的d为全局变量,在没有关键字声明的情形下不能改变全局变量,由于字典可变,遵循可变则可变的原则,输出为{'a': 10, 'b': 20}。
    最后,看实验:
    def func(d):
        print(id(d))
        d['a'] = 10
        d['b'] = 20
        print(id(d))
        d = {'a':1, 'b':2}
        print(id(d))
        print(d)

    d = {}
    print(id(d))
    func(d)
    print(d)
    print(id(d))

    执行结果:
    3072243980
    3072243980
    3072243980
    3072244108
    {'a': 1, 'b': 2}
    {'a': 10, 'b': 20}
    3072243980

    展开
     1
     6
  • 程序员人生
    2019-06-14
    第一题,用id()打印出来后可以证明,l1和l2不是同一个对象,l2和l3是同一个对象。由于列表是可变的,所以l1和l2指向不同的内存区域。
    第二题,做了一下修改,如下:
    def func(d):
        d['a'] = 10
        d['b'] = 20
        d={'a':1,'b':2}

    d={}
    func(d)
    print(d)

    执行结果:
    {'a': 10, 'b': 20}

    d = {'a': 1, 'b': 2}应该是指向了新的对象


    展开
    
     3
  • Wing·三金
    2019-06-16
    # C++

    - 按值传递:拷贝参数的值构建新的变量传递到函数
    - 按引用传递:把参数的引用(i.e. 地址)传递到函数

    # Python

    - 按赋值传递/按对象的引用传递
    - 凡是对对象本身进行的操作,都会影响传递的原对象;凡是生成了新对象的操作,都不会影响传递的原对象
    - 正如【一个人可以死两次,第一次是肉体死去,第二次是当没人记得它的时候】,python 中如果有多个变量指向同一个对象,那么当删除一个变量时并不会真正删除其所指定的对象;只有当所有指定该对象的变量都被删除时,python 才会回收该对象所占用的资源
    - 一般原则:对于不可变的数据类型,operator 等操作会返回新的对象,不会影响原对象;对于可变的数据类型,任何对【对象本身】的操作都会影响所有指向该对象的变量
    - 补充上一条:e.g. 对于 list 而言,l += [1] 和 l = l + [1] 不同!前者是在 l 本身的末尾添加新元素,后者是在 l 的基础上添加新的元素并返回新的对象
    - 在工程上,偏爱类似于上一条后者的作法——即通过【创建新的对象+将其返回】的作法,来减少出错的概率

    # 思考题

    1. l1 与 l2 不同,l3 与 l2 同;
    2. 严格来说,如果没有上下文,这是一段错误的代码,因为没有预先定义 d 变量;不妨假设在第 6 行之前补充语句 d = {},则输出结果为 {'a': 10, 'b': 20},因为 func 中前两行才是改变了对象的操作。而第 3 行只是将函数中的局部变量 d 指向了新的字典 {'a': 1, 'b': 2},但全局变量 d 仍然指向着刚刚被修改过的字典对象。
    展开
    
     2
  • SCAR
    2019-06-14
    第一题:l2和l3指向同一个对象,l2和l1不指向同一个对象。这个题的关键要点是要了解list对象是没有“内存驻留”机制的,这点和整数对象对小于256的数采用的“内存驻留”是截然不同的,所以l1和l2不是指向同一对象。而l3=l2,这就是让l3指向l2指向的对象,很显然l3和l2指向的是同一个对象。
    第二题:题目里的d = {'a': 1, 'b': 2}应该是顶格的吧,估计是老师手误或是编辑器出问题了,不然没意义。如果是这样,print(d),输出应该是{'a': 10, 'b': 20}。
    
     2
  • KaitoShy
    2019-06-14
    1. l2和l3是一个,l1不是。可以通过id(l2),id(l1),id(l3)验证。
    2. d不是没有初始化么。输出错误吧。如果在使用函数func(),将d初始化为d={},输出{'a':10, 'b':20}.原因:前两个改变了对象的值。后面是创建了新对象赋值给了本地对象。
    
     2
  • 张丽娜
    2019-06-14
    def my_func2(b):
        print('a的值是{}'.format(a))
        print('b的值是{}'.format(a))
        b = 2
        print('b的值是{}'.format(b))
        return b


    a = 1
    a = my_func2(a) #这句话so 重要,重新用返回值对于a进行了赋值,看起来debug来逐步分析很重要啊
    print('a的值是{}'.format(a))
    展开
    
     1
  • 小恶魔
    2019-06-14
    看了这么多关于问题2回复都是结果。我想知道python中对参数赋值不会影响外部的值,这是设定语法,还有什么深层次的原因或设计考虑么,谢谢老师。
     1
     1
  • 大龄程序员在线治掉发
    2020-01-19
    1.肯定不是
    2.d是传递进来的值,不是重新赋值,你改变了他,后面也跟着改变
    
    
  • Paul Shan
    2019-11-16
    思考题
    l1 指向一个对象
    l2和l3指向同一个对象

    a :10,b:2
    
    
  • mercy
    2019-11-12
    对象的id能否理解为指针

    作者回复: 不一样的概念呢

    
    
  • Arthur
    2019-11-12
    可变类型,按引用传递;不可变类型,按值传递。
    
    
  • 1cho糖糖
    2019-11-03
    遇到了下面一个问题

    ```
    def demo1(array):
        array += [4, 5]
        return array


    def demo2(array):
        array = array + [4, 5]
        return array


    a = [1, 2, 3]
    b = [1, 2, 3]

    c = demo1(a)
    print('a list is {}\nc list is {}\na is c :{}'.format(a, c, a is c)) # True
    # 输出结果
    a list is [1, 2, 3, 4, 5]
    c list is [1, 2, 3, 4, 5]
    a is c :True

    d = demo2(b)
    print('b list is {}\nd list is {}\nb is d :{}'.format(b, d, b is d)) # False
    # 输出结果
    b list is [1, 2, 3]
    d list is [1, 2, 3, 4, 5]
    b is d :False

    # 函数内部为什么 array += [4, 5] 与 array = array + [4, 5] 对传入的列表影响结果不同
    ```
    展开
    
    
  • 自由民
    2019-10-03
    总结:Python中参数传递既不是传值也不是传引用,而是赋值传递,或传对象的引用。不是指向一个具体的内存地址,而是指向具体的对象。
    如果对象是不变的,改变对象会新建一个对象,并将其中一个变量指向该对象,其它变量不变。如果对象是可变的,改变一个变量时,其它所有指向该对象的变量都会受影响。要想在函数中改变对象,可以传入可变数据类型(列表,字典,集合),直接改变;也可以创建一个新对象,修改以后返回。建议用后者,表达清晰明了,不易出错。
    思考题1:
    l2与l3指向同一对象,与l1不同。
    # 思考题1
     l1 = [1,2,3,4]
     l2 = [1,2,3,4]
     l3 = l2
     print(id(l1), id(l2), id(l3))
    思考题2
    {"a":10, "b":20}
    课程的练习代码: https://github.com/zwdnet/PythonPractice
    展开
    
    
  • 2020
    2019-09-10
    思考题一:
    print(l1 is l2) #False
    print(l3 is l2) #True
    l1和l2指向的是不同对象,l3和l2指向同一对象。l2 = [1,2,3],Python是直接新建了一个对象,然后将l2指向它,不是先在内存中查找是否存在相同值得对象是否已经创建过
    
    
  • 建强
    2019-09-09
    思考题1:
    l1、l2指向不同的对象,l2和l3指向同一对象。

    思考题2:
    d最后的输出是:{'a': 10, 'b': 20}
    
    
  • R
    2019-08-27
    请问老师,return返回b,b是一个引用,还是一个对象呢。
    
    
  • 木易
    2019-08-06
    为什么第一题中的l1和l2不指向同一个对象,但是a=1, b=1中的a和b却指向同一个对象?
     1
    
我们在线,来聊聊吧