Python - 如何在不使用deepcopy的情况下复制对象(因此它不会引用旧对象)?

时间:2014-01-19 13:49:05

标签: 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 wall.rect_x

walls()

打印:

50
50

但我想打印它

40
50

我想在游戏中创建各种“墙”。那些墙可能有很多类似的数据,但也有一些不同。所以我想要一些可用于复制的墙对象,然后在不同的墙上设置不同的属性。如果我使用简单副本,那么如果我更改复制对象中的任何内容,则所有其他对象也将更改该值。我可以使用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

3 个答案:

答案 0 :(得分:0)

如果它是一个简单的列表(没有任何可变对象),你可以使用:List [:]或Dict.copy()

答案 1 :(得分:0)

我会这样做:

  1. 将所有参数更改为关键字参数
  2. 向Wall构造函数添加wall=关键字arg。
  3. 如果设置了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)
    

答案 2 :(得分:0)

最终,这并不是你应该如何做到这一点。相反,请考虑制作一个classmethod,它将同时定义整个范围的墙壁。有点像...

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)