• chap8-fluent python


    浅拷贝 VS 深拷贝

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    # In[]
    # list 生成一个新的引用对象,只是用alst完成初始化
    alst = [1,2,3,4,5]
    blst=list(alst)
    alst.append(6)
    print(blst)
     
    # In[]
    alst = [1,2,3,4,5]
    blst=alst # 浅拷贝,两者同时变化
    alst.append(6)
    print(blst)
     
    # In[]
    from  copy import copy
     
    alst = [1,2,3,4,5]
    blst=alst.copy() # 浅拷贝,两者同时变化
    alst.append(6)
    print(blst)
     
    # In[]
    import  copy
    alst = [1,2,3,4,5]
    blst=copy.deepcopy(alst) # 深拷贝,可以认为是用alst初始化一个新的对象
    alst.append(6)
    print(blst)

     

    此处,对可变类型而言,深拷贝其实就是创建了一个新的引用对象,可以认为原来的只是用来做初始化用的。新旧有变化对彼此都没有影响了。浅拷贝可以认为就是起了个别名。

     

     

    由于这层原因,当可变类型作为函数参数时,尤其要谨慎处理。首先考虑初始化,如果存在None,该怎么处理,其次如果你不想修改传入参数的值,那么要给类或者函数的属性创建一个副本或者说只是拿传入的参数作为初始化,务必保证,函数内部修改可变类型变量时,形参传入的变量不会受到影响。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    '''
    the default value of paramter is None
    '''
    import copy
    # tag::BUS_CLASS[]
    class Bus:
     
        def __init__(self, passengers=None):
            if passengers is None:
                self.passengers = []
            else:
                self.passengers = list(passengers)
     
        def pick(self, name):
            self.passengers.append(name)
     
        def drop(self, name):
            self.passengers.remove(name)
    # end::BUS_CLASS[]
     
    bus1 = Bus(['a','b','c'])
    bus2 = copy.copy(bus1)
    bus1.pick('d')
    bus1.drop('a')
    print(bus2.passengers)
    bus3= copy.deepcopy(bus1)
    print(bus3.passengers)
    bus1.pick('a')
    bus1.drop('d')
    print(bus3.passengers)
    print(bus1.passengers)

      

    此时如果对默认参数处理不好,会引起很诡异的事情。但是如果用list生成一个新的对象,就会避免这个问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    '''
    Mutable Types as Parameter Defaults:Bad Idea
    '''
     
     
    # tag::HAUNTED_BUS_CLASS[]
    class HauntedBus:
        """A bus model haunted by ghost passengers"""
     
        def __init__(self, passengers=[]):  # <1>
            # should be list function to initialization the attribute
            self.passengers = passengers #list(passengers)  # <2>
     
        def pick(self, name):
            self.passengers.append(name)  # <3>
     
        def drop(self, name):
            self.passengers.remove(name)
    # end::HAUNTED_BUS_CLASS[]
     
    bus1 = HauntedBus(['Alice', 'Bill'])
    print(bus1.passengers)
    bus1.pick('Charlie')
    bus1.drop('Alice')
    print(bus1.passengers)
     
    bus2 = HauntedBus()
    bus2.pick('Carrie')
    print('bus2.passengers:',bus2.passengers)
     
    bus3 = HauntedBus()
    print('bus3.passengers:',bus3.passengers)
    bus3.pick('Dave')
    print('bus3.passengers:',bus3.passengers)
    print(bus2.passengers is bus3.passengers)
    print('bus1.passengers:',bus1.passengers)

      

     

    还有,这个程序,把形参改变了,本来不该改变的。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    '''
    here the attribute passengers should be initialized using a list func.
     
    '''
     
    # tag::TWILIGHT_BUS_CLASS[]
    class TwilightBus:
        """A bus model that makes passengers vanish"""
     
        def __init__(self, passengers=None):
            if passengers is None:
                self.passengers = []  # <1>
            else:
                # this can change the passengers when you change self.passengers
                self.passengers = passengers  #<2>
     
        def pick(self, name):
            self.passengers.append(name)
     
        def drop(self, name):
            self.passengers.remove(name)  # <3>
    # end::TWILIGHT_BUS_CLASS[]
     
    basketball_team = ['Sue', 'Tina', 'Maya', 'Diana', 'Pat']
    bus = TwilightBus(basketball_team)
    bus.drop('Tina')
    bus.drop('Pat')
    print(basketball_team)

      

    这几个程序大家都看到了,其实很关键的一个地方是list函数的使用。test =  list(alst)相当于将alst 进行深拷贝,改变alst时,test不会随之改变,改变test时,alst也不会有影响。也可以理解为将alst作为参数,对元素逐个转换,生成一个新的list并返回给test。因此,两者之间不再有影响。

  • 相关阅读:
    倒数 3 天|RocketMQ 能力全景图即将发布,定义下一代消息队列未来方向
    论文阅读【Sensor-Augmented Egocentric-Video Captioning with Dynamic Modal Attention】
    港科夜闻|香港科技大学校长叶玉如教授,新加坡国立大学曾运雄博士:发现阿尔茨海默病新疗法...
    一文搞懂EMAS Serverless小程序开发|电子书免费下载
    macOS中安装zsh,并配置些重要插件
    WiFi模块在智能家居中的应用与优化
    (附源码)ssm教培管理系统 毕业设计 230932
    前端数据可视化之【series、series饼图配置】配置项
    黑猫带你学Makefile第3篇:Makefile基本语法
    emment语法
  • 原文地址:https://www.cnblogs.com/jianyingzhou/p/16030784.html