Erster einsatz von property

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Martin Kalbfuß
User
Beiträge: 21
Registriert: Freitag 23. Mai 2008, 09:17

Hallo zusammen.
Ich will gerade "properties" testen, und stoße aber auf ein Problem bezüglich der Setter-Methode. in der Klasse Jaeger, welche Sprite als Metaklasse verwendet wird bei image = "Schuss.bmp" die Settermethode nicht aufgerufen.

Bei self.rect = self.image.get_rect() die Getter-Methode aber schon. Er beschwert sich dann, dass __Bild nicht vorhanden sei.

Was mich auch verwundert ist, dass bei self.rect = self.image.get_rect() ein zusätlicher Parameter übergeben wird. In den ganzen Beispielen die ich gefunden habe, wird der Getter-Methode kein Parameter übergeben.

Warum funktioniert mein Ansatz nicht? Hab ich was wichtiges übersehen?

Code: Alles auswählen


#-----------------------------------------------
class Sprite(type):
#-----------------------------------------------

		def __init__(cls, name, bases, dict):
#´´´´´´´´´´´´´´´´´´´´´

			cls.image = property(cls._erhalte_Bild, cls._lade_Bild)

		def start(cls, Periodendauer):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´

			cls.Gruppe = pg.sprite.Group()
			cls.Periodendauer = Periodendauer
			cls.Startzeit = pg.time.get_ticks()
			#cls.image.convert()

		def _lade_Bild(cls, Wert):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´´

			cls.__Bild = pg.image.load("data/Grafiken/" + Wert)
			cls.__Bild.convert()	

		def _erhalte_Bild(cls, obj):
#´´´´´´´´´´´´´´´´´´´´´´´´´

			return cls.__Bild

		def erneuern(cls, Ereignisse):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´

			Status = pg.time.get_ticks() - cls.Startzeit > cls.Periodendauer
			if Status:
				cls.Startzeit = cls.Periodendauer

			cls.Gruppe.update(Status, Ereignisse)

		def ausgeben(cls, Ziel):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´

			cls.Gruppe.draw(Ziel)

#-----------------------------------------------
class Schuss(pg.sprite.Sprite):
#-----------------------------------------------

	__metaclass__ = Sprite

	image = "Schuss.bmp"

	def __init__(self, x, y):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´

		pg.sprite.Sprite.__init__(self)

		self.rect = self.image.get_rect()
		self.midbottom = x, y

		self.Gruppe.add(self)

	def update(self, Status, Ereignisse):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´

		if Status == True:
			self.rect.top += 1;

		if self.rect.bottom < 0:
			self.Gruppe.remove(self)

#-----------------------------------------------
class Jaeger(pg.sprite.Sprite):
#-----------------------------------------------

	__metaclass__ = Sprite

	image = "Gegner.png"

	def __init__(self, x):
#´´´´´´´´´´´´´´´´´´´´´´´´

		pg.sprite.Sprite.__init__(self)

		self.rect = self.image.get_rect()
		self.midbottom = x, -self.rect.height

		self.Gruppe.add(self)

	def update(self, Status, Ereignisse):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´

		if Status == True:
			self.rect.top -= 1;

		if self.rect.top > 240:
			self.Gruppe.remove(self)

#-----------------------------------------------
if __name__ == "__main__":
#-----------------------------------------------

	pg.init()
	bildschirm = pg.display.set_mode((320,240))

	spielstatus = True

	Jaeger(50)
	
	Jaeger.start(3000)

	while spielstatus:
	
		ereignisse = pg.event.get()

		for ereignis in ereignisse:
			if ereignis.type == QUIT: spielstatus = False

		Jaeger.erneuern(ereignisse)
		Jaeger.ausgeben(bildschirm)

		pg.display.flip()

Zuletzt geändert von Martin Kalbfuß am Dienstag 27. Mai 2008, 13:06, insgesamt 1-mal geändert.
BlackJack

"Erster Einsatz von property" ist gut. Da hätte ich jetzt nicht erwartet gleich ein Beispiel mit Metaklassen vermischt zu sehen.

Mir ist das ein wenig zu viel Code den ich nicht ausführen kann. Verpack Dein Problem doch noch einmal in ein minimales Stück Quelltext, mit den Problemen, das man auch nachvollziehen kann.
Martin Kalbfuß
User
Beiträge: 21
Registriert: Freitag 23. Mai 2008, 09:17

Code: Alles auswählen


#encoding: utf-8

import pygame as pg
from pygame.constants import *

#-----------------------------------------------
class Sprite(type):
#-----------------------------------------------

		def __init__(cls, name, bases, dict):
#´´´´´´´´´´´´´´´´´´´´´

			cls.image = property(cls._erhalte_Bild, cls._lade_Bild)

		def _lade_Bild(cls, Wert):
#´´´´´´´´´´´´´´´´´´´´´´´´´´´´

			cls.__Bild = pg.image.load("data/Grafiken/" + Wert)
			cls.__Bild.convert()	

		def _erhalte_Bild(cls, obj):
#´´´´´´´´´´´´´´´´´´´´´´´´´

			return cls.__Bild

#-----------------------------------------------
class Jaeger(pg.sprite.Sprite):
#-----------------------------------------------

	__metaclass__ = Sprite

	image = "Gegner.png"

	def __init__(self, x):
#´´´´´´´´´´´´´´´´´´´´´´´´

		pg.sprite.Sprite.__init__(self)

		self.rect = self.image.get_rect()
		self.midbottom = x, -self.rect.height

		self.Gruppe.add(self)

#-----------------------------------------------
if __name__ == "__main__":
#-----------------------------------------------

	pg.init()
	bildschirm = pg.display.set_mode((320,240))

	Jaeger(50)
	



Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

Die Klasse ist in `Sprite.__init__` ja bereits erstellt und wird lediglich noch initialisiert. ``cls.image`` ist also 'Gegner.png' und wird dann mit dem property-Objekt überschrieben.
Martin Kalbfuß
User
Beiträge: 21
Registriert: Freitag 23. Mai 2008, 09:17

Die __init__-Methode der Klasse wird also erst nach ihrer erzeugung aufgerufen!? Lieg ich damit richtig, dass ich also die "property" in der __new__-Methode der Klasse erstellen muss?
Benutzeravatar
Trundle
User
Beiträge: 591
Registriert: Dienstag 3. Juli 2007, 16:45

In `__new__` ist `image` auch bereits vorhanden (im Klassendict, das als vierter Parameter übergeben wird). Da findet also auch keine Zuweisung statt, bei der ein property-Objekt beteiligt wäre.
Martin Kalbfuß
User
Beiträge: 21
Registriert: Freitag 23. Mai 2008, 09:17

Gibt es überhauot eine Möglichkeit ein Klassenattribut als "property" zu definieren, bevor die Werte zugewiesen werden?

Danke
midan23
User
Beiträge: 147
Registriert: Sonntag 21. Mai 2006, 21:41
Wohnort: Müchen
Kontaktdaten:

Hier ein kleines Beispiel zu Properties:

Code: Alles auswählen

class PropertyTest(object):

    def __init__(self, wert):
        self._wert = wert

    def _get_wert(self):
        return self._wert

    def _set_wert(self, neuer_wert):
        self._wert = neuer_wert

    wert = property(_get_wert, _set_wert)
Wichtig sind zwei Sachen
  • Die Klasse muss direkt oder indirekt von object abgeleitet sein
  • Die Property wird auf der gleichen Ebene wie Methoden definiert
Hoffe etwas Licht ins Dunkel gebracht zu haben ;-)
BlackJack

Ich frage mich wozu überhaupt die Metaklasse gebraucht wird. Kann man da nicht mit ganz normaler Vererbung arbeiten? Warum so viel Magie?
Martin Kalbfuß
User
Beiträge: 21
Registriert: Freitag 23. Mai 2008, 09:17

Die Magie :) wie du sie nennst, Ein schöner Ausdruck dafür, ist nötig da ich sozusagen Klassenfunktionen erben will. Was, so weit ich richtig liege nicht mit normaler Vererbung funktioniert. Daher die Metaklasse. Das problem ist eigentlich erst einmal garnicht die "property", sondern die Metaklasse. Ich hab nur gedacht es liegt an der "property".

Trotdem ergibt sich hier noch eine Frage. Ist objekt wirklich nötig. Ich benutze Python 2.5 und es ist mir bisher noch nicht aufgefallen das ich das noch machen müsste. Vielleicht hatte ich einfach nur Glück, oder hab was falsch interpretiert.

Meine Überlegung ist nun folgende. Wenn ich das erstellen der "property" nicht früher hinbekomme, muss halt die Zuweisung später erfolgen. Also das Codefragment image = "blablabla.png" in die __init__-Funktion der erbenden Klasse einfügen. Werd das ganze gleich mal ausprobieren.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Auch wenn ich denke, dass deine Magie unangebracht ist, hier mal ein Beispiel:
http://paste.pocoo.org/show/54758

Metaklassen sind böse. Immer. Naja, jedenfalls bei Allem, was dir im normalen Leben unterkommen wird ;)

Zu `object`:
http://www.geocities.com/foetsch/python ... lasses.htm
Martin Kalbfuß
User
Beiträge: 21
Registriert: Freitag 23. Mai 2008, 09:17

Danke für die Links. Einen kannte ich sogar schon. Habe viel im Internet gestöbert. Und ja, es würde auch anders gehen, wäre aber bei weitem nicht so elegant. Ich hab schon viel drüber nachgedacht. Habe Code geschrieben und ihn wieder verworfen.
Die andere Möglichkeit wäre die Dinge die für alle Instanzen einer Klasse gelten sollen der Gruppe zugewiesen werden. So hatte ich das zuerst. Dann allerdings muss ich jedesmal eine neue Gruppenklasse für jeden neuen Objekttyp erstellen, zusätzlich zu der Objektklasse. Das wäre dann ziemlich viel überflüssiger Code meiner Meinung nach.
Allerdings ist das mit den Metaklassen nicht ohne.
Aber Magie ist doch was tolles. Wer möchte nicht zaubern können. Ich mache das ganze auch, weil ich die neuen Pythonfunktionen erkunden will.

Aber nun zurück zum Problem.

Was ich suche, ist eine Funktion, der erbenden Klasse, welche beim erstellen der Klasse aufgerufen wird.

Die Zuweisung des Bildes soll also nach dem erstellen der "property" passieren, und automatisch, so das kein Extra aufruf einer Klassenmethode nötig ist. Gibt es so eine Funktion in einer Klasse. Die metaklasse hat ja eine __init__-Funktion hat die erbende Klasse so etwas auch? Und wenn ja, wann wird sie ausgeführt. NAch oder vor der __init__-Methode der Metaklasse.

Sorry für die vielen schwierigen Fragen. Aber vielleicht kann ja der ein oder andere hier auch noch was aufschnappen.

Danke übrigens für die viele Ressonanz. Gute leute hier. War schon on in Foren unterwegs, wo garnichts kam, oder die Leute super unfreundlich waren, wenn ihnen die Fragen nicht gepasst haben.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

audax hat geschrieben:Auch wenn ich denke, dass deine Magie unangebracht ist, hier mal ein Beispiel:
http://paste.pocoo.org/show/54758
Anstatt die Klasse zu erstellen und dann __name__ zu setzen würde man wohl eher type() direkt aufrufen -- etwa so:

Code: Alles auswählen

def createClass(name, *args):
    return type(name, (object,),
                dict((attr, property(getGetter('_'+attr),
                                     getSetter('_'+attr)))
                     for attr in args))
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Hatte ich so, aber ich den jetztigen Weg irgendwie...schöner.

Und warum type() und damit eine seltsame Syntax wenn ich es so idiomatisch und ebenso eindeutig schreiben kann? :]
Ist allerdings auch echt nicht für den Produktivgebrauch gedacht ^^
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

audax hat geschrieben:Hatte ich so, aber ich den jetztigen Weg irgendwie...schöner.

Und warum type() und damit eine seltsame Syntax wenn ich es so idiomatisch und ebenso eindeutig schreiben kann? :]
Weil du eine leere Klasse erstellst und sie monkeypatcht, das schaut für mich seltsamer aus, als ``type()``. Übrigens hat der Aufruf von birkenfeld keine seltsame Syntax sondern gar keine, bzw die ganz normale Syntax die man auch von Python gewohnt ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

Meine Güte, ich hatte halt die Funktion mal auf Monkeypatching umgeschrieben und hatte sie nicht im SVN.

Mir sind jedenfalls beide Möglichkeiten recht aber ich hoffe doch, sowas nicht in Produktivcode zu sehen :D
Antworten