4 Stimmen

Verwendung und Initialisierung von Python Klassenattributen

Ich habe ein paar Fragen zu Klassen in Python.

Es gibt die Bullet-Klasse, die ein abstraktes Geschoss in einem Computerspiel darstellt, und es wird eine Menge ihrer Instanzen geben (ich versuche ein "bullet hell" Spiel zu machen :). Die Instanzen haben das gleiche Bild und die gleiche Bewegungsfunktion, während sie sich an unterschiedlichen Positionen befinden. Im folgenden Code habe ich versucht, gemeinsame Dinge in Klassenattributen zu platzieren und ihre Werte mit der class_init-Klassenmethode zu laden. Das Ziel ist es, Daten zu deduplizieren und etwas Speicher zu sparen.

Q1: Ist diese class_init-Methode das richtige Vorgehen? Vielleicht gibt es einen eleganteren Weg.

Q2: Wird sich tatsächlich der Speicherverbrauch verbessern?

GELÖST: Vielen Dank für eure Tipps, alle! Ich denke, ich lag mit meinem Code nicht völlig falsch, obwohl er verbessert werden könnte. Ich muss noch über Metaklassen, Slots und Profiling in Python lesen. Es gibt also noch einen langen Weg zu gehen, seufz. Trotzdem, vielen Dank!

class Bullet(object):
    @classmethod
    def class_init(cls, image, movement_function):
        cls.image = image
        cls.movement_function = movement_function

    def __init__(self, pos):
        super(Bullet, self).__init__()
        self.pos = pos

if __name__ == '__main__':
    Bullet.class_init('sprite.png', lambda x: x + 1)
    b1 = Bullet((10,10))
    b2 = Bullet((20,20))
    print 'pos', id(b1.pos) == id(b2.pos)
    print 'image', id(b1.image) == id(b2.image)
    print 'movement_function', id(b1.movement_function) == id(b2.movement_function)

1voto

Marcin Punkte 46457

Q1: Ist diese class_init Methode das Richtige? Vielleicht gibt es einen eleganteren Weg.

Es ist nicht falsch. Vielleicht wäre der idiomatischere Weg, dies als __init__ in einer Metaklasse zu tun, aber jeder Weg ist in Ordnung.

Q2: Wird es tatsächlich den Speicherverbrauch verbessern?

Wahrscheinlich nicht viel, weil das Bild und die Funktion nicht kopiert werden - nur die Referenz zu diesen Objekten wird kopiert.

Der Weg zu lernen, ob etwas die Geschwindigkeit oder den Speicherverbrauch verbessern wird, ist es zu profilieren. Bevor Sie das Problem identifizieren, führen Sie keine Tricks durch, die etwas optimieren könnten.

cls.movement_function = movement_function

Warum ist movement_function nicht einfach eine Methode?

1voto

zmo Punkte 23703

Q1: Ist diese class_init-Methode das Richtige? Vielleicht gibt es einen eleganteren Weg.

Ob dies richtig ist oder nicht, ist schwer zu sagen. Aber es ist definitiv keine schlechte Art, dies zu tun. Sie verwenden eine Klassenmethode, um Klassenattribute zu definieren, das ergibt Sinn und sieht gut aus. Wenn man es aus der Sicht der OOP betrachtet, werden die Klassendaten in einer Klassenmethode gekapselt.

Dennoch ist die movement_function ein Verhalten, das auf einem Instanzmember arbeitet. Es sollte also besser als Instanzmethode definiert werden und bei Bedarf durch Klassenvererbung geändert werden, falls Sie verschiedene movements benötigen.

Q2: Wird dies tatsächlich den Speicherverbrauch verbessern?

Für das Bild hängt es wirklich davon ab, wie Sie es initialisieren. Stellen Sie sich Folgendes vor:

class Bullet2:
    def __init__(self, image):
        self.image = image

wenn Sie Folgendes tun:

für _ in range(1,10000):
    with open('/Pfad/zum/Bild.png', 'r') as f:
        Bullet2(YourImage(f.read()))

dann werden 10000 Instanzen des Bildes erstellt. Das wird viel Speicher verbrauchen.

Wenn Sie jedoch Folgendes tun:

with open('/Pfad/zum/Bild.png', 'r') as f:
    img = YourImage(f.read())
    for _ in range(1,10000):
        Bullet2(img)

dann haben Sie 10000 Verweise auf dieselbe Instanz. Das würde die gleiche Menge Speicher wie bei Ihrem verbrauchen:

with open('/Pfad/zum/Bild.png', 'r') as f:
    img = YourImage(f.read())
    Bullet.class_init(img)
    for _ in range(1,10000):
        Bullet()

Wenn Ihre Lösung eine gewisse Eleganz hat, geht es darum, ob Sie das Bild aller Instanzen mit einer einzelnen Methode ändern möchten oder nicht. Doch ich würde lieber eine Methode namens setup_image() verwenden, anstelle der zu allgemeinen class_init(), die nicht darüber informiert, was sie tut.

Wenn Sie das Bild jeder Instanz einzeln ändern möchten, dann ist es besser, einen Verweis innerhalb von Bullet zu verwenden, wie ich es bei Bullet2 mache:

class Bullet2:
    def __init__(self, image):
        self.image = image
    def change_image(self, img):
        self.image = img

Bezüglich der Festlegung eines Rückrufs auf eine Funktion als Klassenmember oder Erstellung einer Methode für Ihre Klasse, wird es in Bezug auf den Speicher äquivalent sein, obwohl die zweite Option besser sein wird, da sie besser lesbar ist und das Verhalten Ihrer Klasse definiert. Wenn Sie dann ändern möchten, was die Methode tut, können Sie Klassenvererbung verwenden.

1voto

chepner Punkte 440093

Die idiomatischere Möglichkeit, eine Klasse anzupassen, besteht darin, eine Fabrikfunktion zu definieren, die eine Unterklasse von Bullet zurückgibt. Wenn Sie sich nicht um den Namen der resultierenden Unterklasse kümmern, können Sie darauf verzichten, cls_name zu einem Parameter zu machen und stattdessen einen fest kodierten Namen in make_bullet verwenden.

class Bullet(object):
    def __init__(self, pos):
        super(Bullet, self).__init__()
        self.pos = pos

def make_bullet(cls_name, image, movement_function):
    return type(cls_name, (Bullet,), {'image': image,
                                      'movement_function': movement_function })

if __name__ == '__main__':
    MyBullet = make_bullet('MyBullet', 'sprite.png', lambda x: x+1)
    b1 = MyBullet((10,10))
    b2 = MyBullet((20,20))
    print 'pos', id(b1.pos) == id(b2.pos)
    print 'image', id(b1.image) == id(b2.image)
    print 'movement_function', id(b1.movement_function) == id(b2.movement_function)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X