2014-01-19 42 views
1

我有這樣的代碼:Python - 如何複製對象(所以它不會引用舊對象),而不使用deepcopy?

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 
+0

你爲什麼不願意使用'deepcopy'? –

+0

因爲它很慢。如果我只依靠深層拷貝,以後它可能會降低性能。所以我希望有一些其他的解決方案,可能會有更好的表現。 – Andrius

+1

您能否顯示Wall的定義,或者更好的創建一個[SSCCE](http://sscce.org/)?明顯的定義不應該導致你所看到的行爲。 – delnan

回答

0

我這樣做:

  1. 改變所有參數關鍵字參數,
  2. 將一個wall=關鍵字arg添加到Wall構造函數中。
  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) 
    
+0

酷,我自己做了類似的事情:) – Andrius

0

如果它是一個簡單的列表(沒有任何可變對象),你可以使用:列表[:]或Dict.copy()

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) 
相關問題