Python—如何在不使用deepcopy的情况下复制对象(这样它就不会引用旧对象)?

Python—如何在不使用deepcopy的情况下复制对象(这样它就不会引用旧对象)?,python,reference,copy,Python,Reference,Copy,我有以下代码: import pygame import block as b import constants as c import copy def walls(): walls_list = [] wall_proto = b.Wall(c.WHITE, 40, 40, 20, 80) wall = copy.copy(wall_proto) wall.rect_x = 50 print wall_proto.rect_x print w

我有以下代码:

import pygame
import block as b
import constants as c
import copy
def walls():
    walls_list = []

    wall_proto = b.Wall(c.WHITE, 40, 40, 20, 80)
    wall = copy.copy(wall_proto)
    wall.rect_x = 50
    print wall_proto.rect_x
    print wall.rect_x

walls()
印刷品:

50
50
但我想把它打印出来

40
50
我想在我的游戏中创造各种各样的“墙”。这些墙可能有很多相似的数据,但也有些不同。所以我想有一些墙对象,可以用来复制,然后在不同的墙上设置不同的属性。若我使用简单复制,那个么若我更改了复制对象中的任何内容,所有其他对象也会更改该值。我可以用deepcopy,但速度很慢。是否有比deepcopy更好的解决方案

更新

按要求的墙体等级:

class Wall(pygame.sprite.Sprite):
    def __init__(self, color, x, y, width, height):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.Surface([width, height])
        self.image.fill(color)

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        #to get/set values
        self._width = width
        self._height = height

    @property
    def rect_x(self):
        return self.rect.x
    @property
    def rect_y(self):
        return self.rect.y
    @property
    def width(self):
        return self._width
    @property
    def height(self):
        return self._height

    @rect_x.setter
    def rect_x(self, value):
        self.rect.x = value

    @rect_y.setter
    def rect_x(self, value):
        self.rect.y = value

    @width.setter
    def width(self, value):
        self._width = value

    @height.setter
    def height(self, value):
        self._height = value
如果它是一个简单的列表(没有任何可变对象),您可以使用:list[:]或Dict.copy()

我会这样做:

  • 将所有参数更改为关键字参数
  • wall=
    关键字arg添加到wall构造函数
  • 如果设置了
    wall
    ,请将值复制到新实例中,然后根据其他参数进行设置。像这样:

    class Wall(pygame.sprite.Sprite):
        def __init__(self, color=None, x=None, y=None, width=None, height=None, wall=None):
            pygame.sprite.Sprite.__init__(self)
            # check parameters are valid
            assert any([color and x and y and width, wall]), "invalid arguments"
            # assign parameters from given wall or parameters
            x      = x or wall.rect_x
            y      = y or wall.rect_y
            color  = color or wall.color
            height = height or wall.height
            width  = width or wall.width
            ...
    
    然后您可以编写如下代码:

    wall1 = Wall(c.WHITE, 40, 40, 20, 80)
    wall2 = Wall(color=c.BLUE, wall=wall1)
    

  • 归根结底,你不应该这样做。考虑一下,制作一个“代码>类方法< /COD>”,它将同时定义整个墙的范围。类似于

    class Wall(pygame.sprite.Sprite):
        def __init__(self, color, x, y, width, height):
            pygame.sprite.Sprite.__init__(self)
    
            self.image = pygame.Surface([width, height])
            self.image.fill(color)
    
            self.rect = self.image.get_rect()
            self.rect.x = x
            self.rect.y = y
            # since your properties are only getters and setters, don't use them
            self.width = width
            self.height = height
    
        @classmethod
        def make_walls(cls, color, coords):
            """Makes a grouping of walls of a specified color, given
            a list of (x, y, width, height) tuples"""
            list_of_walls = []
            for details in coords:
                x, y, width, height = details
                wall = cls(color, x, y, width, height)
                list_of_walls.append(wall)
            return list_of_walls
            # or MUCH less clear:
            # return [cls(color, *details) for details in coords)]
    
    然后,您可以通过以下操作制作任何您喜欢的墙:

    wall_locations = [
        (1, 1, 1, 1),
        (1, 2, 1, 1),
        (1, 3, 1, 1),
        (1, 4, 1, 1),
        ... ]
    new_walls = b.Wall.make_walls(c.WHITE, wall_locations)
    

    为什么您不喜欢使用
    deepcopy
    ?因为它很慢。如果我只依赖deepcopy,以后可能会降低性能。因此,我希望有一些其他的解决方案,可能会有更好的性能。你能展示一下
    墙的定义,或者更好地创建一个墙吗?显而易见的定义不应该导致你看到的行为。请问
    wall\u proto
    的性质是什么?你为什么不写
    wall=b.wall(c.WHITE,50,40,20,80)
    ?第二个参数是50而不是40。但即使是相同的,我认为名为
    wall
    的实例与名为
    wall\u proto
    的实例将是不同的对象。酷,我自己也做了类似的事情:)