Konstruktur mit altem Selbst

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
gecko
User
Beiträge: 47
Registriert: Samstag 9. Juni 2007, 10:48

Donnerstag 1. November 2007, 11:53

Spricht etwas gegen die Überschreiben des Konstruktors mit einem alten selbst?

Code: Alles auswählen

class foo:
	def __init__(self, data='initial data', oldfoo=None):
		if oldfoo:
			self.data = oldfoo.data
		if data:
			self.data = data
			
	def __str__(self):
		return 'my data: ' + self.data	
		

if __name__=='__main__':
	f = foo()
	print f
	
	g = foo('new data')
	print g
	
	h = foo('', g)
	print h
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 1. November 2007, 12:16

Außer dem Fakt, dass wenn du sowohl `data` als auch `oldfoo` angibst, `oldfoo` keine Wirkung hat eigentlich nichts.

Ich mache es jedoch etwas anders:

Code: Alles auswählen

class Table(dict):
    """Simplified version of frozendict from 
    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/414283
    
    This implementation is not hashable nor does it try to be.
    It is meant to be used as a drop-in replacement for 'dict'
    and throws AttributeErrors when trying to change it.
    
    Do not expect absolute security from this code, it is only
    meant to catch errors when one mistakenly alters keys in
    this object instead of creating a new Table object based
    on this one.
    
    To create a new Table based on this one use
    >>> Table(old_table, new_key='new_value')
    >>> # or
    >>> Table(old_table, { 'new_key' : 'new_value' })"""

    def _blocked_attribute(obj):
        """This is called when trying to access a attribute which
        modifies the state of this object"""
        # blocked, complain
        raise AttributeError("A Table cannot be modified")
   
    # turn _blocked_attribute into a property
    _blocked_attribute = property(_blocked_attribute)

    # overwrite modifying methods with _blocked_attribute
    __delitem__ = __setitem__ = clear = _blocked_attribute
    pop = popitem = setdefault = update = _blocked_attribute

    def __repr__(self):
        """Display the contents of the Table"""
        return "Table(%s)" % dict.__repr__(self)

    def update(table, updates, *args, **kwargs):
        """Updates a Table environment - it does not alter the Table,
        instead it returns a new Table with the changes applied"""
        # create a new empty dictionary to hold all values
        new_table = dict()
        # choin both dict-like objects together
        all_items = itertools.chain(table.iteritems(), updates.iteritems())

        # add all keys to the dictionary
        for key, value in all_items:
            new_table[key] = value

        # convert the dictionary into a Table and return
        return Table(new_table)
Damit habe ich eine Klasse, die immutable ist und die bei update() eine neue Klasseninstanz ausgibt, die eine aktualisierte Kopie seiner selbst zurückgibt.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
BlackJack

Donnerstag 1. November 2007, 14:07

@gecko: Die Frage ist, was Du durch das zusätziche Argument gewinnst. Du könntest bei dem Aufruf in Zeile 19 ja auch schreiben:

Code: Alles auswählen

h = foo(g.data)
Falls `data` "intern" sein soll kann man auch `copy.copy()` oder eine eigene Methode zum Kopieren eines Objekts benutzen.
gecko
User
Beiträge: 47
Registriert: Samstag 9. Juni 2007, 10:48

Donnerstag 1. November 2007, 15:33

Ich habe jetzt gerade diese Lösung, aber das ist vermutlich Schwachsinn:

Code: Alles auswählen

class foo:
	def __init__(self, data=('initial data','another'), oldfoo=None):
		if oldfoo:
			allmethods = [method for method in dir(oldfoo)]
			for m in allmethods:
				notclass = str(m).find('__') == -1 # isClassMethod?
				if not callable(getattr(oldfoo, m)) and notclass:
					setattr(self,m,(getattr(oldfoo,m)))
		
		if data:
			self.data = data
			
	def __str__(self):
		s = ''
		for d in self.data: s+=' ' + str(d)
		return s

if __name__=='__main__':
	f = foo()
	print 'f: ', f
	
	g = foo(('new data','second'))
	print 'g: ', g
	
	h = foo('', g)
	print 'h: ', h
Ich kann ja einfach self.data = oldfoo.data sagen. Dann muss ich allerdings sicherstellen, dass das Attribut existiert. Hintergrund ist, ich habe eine Klasse mit 30 Attributen. Sollte ich diese auch alle in ein Tupel packen?
BlackJack

Donnerstag 1. November 2007, 16:10

Das sieht sehr kompliziert und fragil aus. Was willst Du überhaupt machen? Und muss das unbedingt in der `__init__()` passieren? Was spricht dagegen `copy.copy()` ausserhalb zu benutzen, oder in einer `copy()`-Methode auf dem Objekt oder zumindest eine Klassenmethode `from_foo()` oder so ähnlich bereit zu stellen!?
gecko
User
Beiträge: 47
Registriert: Samstag 9. Juni 2007, 10:48

Freitag 2. November 2007, 14:51

Hi,

danke für die Antwort.

Was ich eigentlich vorhabe ist das:

ich habe eine Reihe von States S_1, ..., S_N

Der State S_i zum Zeitpunkt i ergibt sich aus dem State zum Zeitpunkt i -1 (S_i-1) und der Beobachtung zum Zeitpunkt i (zusätzlichen Daten).

Jetzt habe ich gedacht, dass ich am besten bei der Erzeugung von S_i , S_i-1 mit auf den Weg gebe, aber das ist wie Du sagst keine gute Idee.

Das ganze verkompliziert sich noch, weil jeder State bis zu M alte States als Datenstruktur mitträgt. Nach M Zeitschritten wird der State auf 0 zurückgesetzt. Am besten wird wohl sein ich habe eine Klasse die alle States von 1 bis M enthält (Klasse Durchlauf) und eine Klasse wie bisher für jeden einzelnen State. Auf beiden Klassen will ich später komplexere Operationen ausführen (Bäume daraus erzeugen z.B.).
Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
Antworten