Python. Связь между экземплярами одного класса через обращение к атрибуту

Рейтинг: 0Ответов: 2Опубликовано: 03.05.2023

Есть один класс. Есть два экземпляра этого класса. Один движется (self.type = 'move'), второй не движется (self.type = 'stay').

Нужно, чтобы второй тоже двигался по координатам первого.

Может ли obj2 апеллируя атрибутом self.type обратиться к obj1, чтобы наследовать его координаты?

Вариант посредника в виде глобальной переменной известен, но нужно чтобы obj2 обращался непосредственно к obj1. Помогите пожалуйста разобраться.

UPD: Важно, чтобы обращение происходило внутри класса, в методе Update, учитывая, что никакая информация вроде названий или индексов копий неизвестна, известен только атрибут self.type.

import pygame

pygame.init()

WIDTH, HEIGHT = WINDOW_SIZE = 800, 600
FPS = 60

window = pygame.display.set_mode(WINDOW_SIZE)
clock = pygame.time.Clock()

objects = []

class ObjectTest:
    def __init__(self, type, x, y):
        objects.append(self)

        self.type = type

        self.color = 'red'
        self.rect = pygame.Rect(x, y, 64, 64)

    def update(self):
        if self.type == 'move':
            self.rect.x += 1
            self.color = 'green'
        if self.type == 'stay':
            # здесь нужно self.rect.x взять у копии с тайпом 'move'
            self.color = 'white'

    def draw(self):
        pygame.draw.rect(window, self.color, self.rect)

obj1 = ObjectTest('move', 100, 100)
obj2 = ObjectTest('stay', 200, 200)

play = True
while play:

    for event in pygame.event.get():

        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            play = False
            pygame.quit()

    for i in objects: i.update()

    window.fill('black')
    for i in objects: i.draw()


    pygame.display.update()
    clock.tick(FPS)

Ответы

▲ 1Принят

Кроме переменных экземпляра класса (то есть self) есть ещё переменные самого класса ObjectTest. Вы можете поместить список objects в переменные класса ObjectTest и при этом обращаться к нему через self, то есть через экземпляр класса (экземпляры имеют доступ к переменным класса):

class ObjectTest:
    # список объектов теперь принадлежит всем объектам класса
    objects = []

    def __init__(self, type, x, y):
        # добавляем новый экземпляр класса в список объектов класса
        self.objects.append(self)
    ...

    def update(self):
        if self.type == 'move':
            self.rect.x += 1
            self.color = 'green'
        if self.type == 'stay':
            # перебираем объекты класса, ищем движущийся объект
            for obj in self.objects:
                # если нашли, то копируем его координату
                if obj.type == 'move':
                    self.rect.x = obj.rect.x
            self.color = 'white'

Внешне это выглядит похоже на использование глобальной переменной, но является более правильным подходом - список objects лежит не в глобальном пространстве, где непонятно, к чему он вообще относится, а лежит в классе, объекты которого он содержит.

Можно пойти дальше и, если у вас только по одному объекту каждого type, то завести словарь, а не список, у которого ключом будет type объекта. Тогда вам даже не нужно будет перебирать объекты, чтобы найти нужный:

class ObjectTest:
    # словарь объектов
    objects = {}

    def __init__(self, type, x, y):
        # добавляем новый экземпляр класса в словарь объектов класса
        self.objects[type] = self
    ...

    def update(self):
        if self.type == 'move':
            self.rect.x += 1
            self.color = 'green'
        if self.type == 'stay':
            # ищем движущийся объект (он может быть ещё не добавлен)
            obj = self.objects.get('move')
            if obj in not None:
                # если нашли, то копируем его координату
                self.rect.x = obj.rect.x
            self.color = 'white'

И type - плохое название для параметра функции, оно перекрывает встроенную функцию. Используйте type_. Вот в переменных класса можно оставить self.type как есть, насколько я помню.

▲ 0

Я видимо не совсем понимаю, что вы хотите сделать.

  1. Может вам просто добавить эту строку:

    self.rect.x += 1 в методе update()

  2. Или добавьте строку:

    objects[1].rect.x = objects[0].rect.x


import sys
import pygame

pygame.init()

WIDTH, HEIGHT = WINDOW_SIZE = 800, 600
FPS = 60

window = pygame.display.set_mode(WINDOW_SIZE)
clock = pygame.time.Clock()

objects = []

class ObjectTest:
    def __init__(self, type, x, y):
        objects.append(self)

        self.type = type

        self.color = 'red'
        self.rect = pygame.Rect(x, y, 64, 64)

    def update(self):
        if self.type == 'move':
            self.rect.x += 1
            self.color = 'green'
        if self.type == 'stay':
            self.color = 'white'
            
# ?          self.rect.x += 1    # может вам просто добавить эту строку ?

    def draw(self):
        pygame.draw.rect(window, self.color, self.rect)
        

obj1 = ObjectTest('move', 100, 100)
obj2 = ObjectTest('stay', 200, 200)
obj3 = ObjectTest('123', 300, 300)

play = True
while play:

    for event in pygame.event.get():

        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            play = False
#            pygame.quit()
            sys.exit()

    for i in objects: 
        i.update()

    window.fill('black')           
    for i in objects: 
        i.draw()

        objects[1].rect.x = objects[0].rect.x       # или попробуйте так 

    pygame.display.update()
    clock.tick(FPS)

введите сюда описание изображения