Klasse nur mit "erlaubten" Variablen ...

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
Pumeluk2
User
Beiträge: 26
Registriert: Samstag 24. März 2007, 11:24

Samstag 4. April 2009, 13:49

Hallo,

nach langer Zeit (in der ich aus beruflichen Gründen keine Zeit hatte mit Python zu "spielen"), hätte ich nun mal wieder gerne ein Problem :D

Ich möchte eine Klasse als Datencontainer benutzen in der aber von ausserhalb nur Variablen (Werte) gelesen und gesetzt werden dürfen, die in der __init__ Prozedur definiert wurden.

Standardmäßig funktioniert ja auch in Python folgendes:

Code: Alles auswählen

class Test:

    def __init__(self):
        self.name = ''


if __name__ == '__main__':
    test = Test()
    test.dumm = 'Hallo'
    print test.dumm
Obwohl "dumm" nicht in __init__ definiert wurde, lässt es sich zur Klasse Test von Aussen hinzufügen.

Nach einigem Suchem habe ich nun folgende Lösung gefunden die scheinbar funktioniert:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8

class Container:

    def __init__(self):
        self.__dict__['first'] = True
        self.name = ''
        self.first = False

    def __setattr__(self, name, value):
        if self.first:
            self.__dict__[name] = value
        else:
            if name in self.__dict__:
                self.__dict__[name] = value
            else:
                raise AttributeError

    def __getattr__(self, name):
        if name in self.__dict__:
            return self.__dict__[name]
        else:
            raise AttributeError

if __name__ == '__main__':
    cont = Container()
    print cont.name
    cont.name = 'hallo'
    print cont.name
    cont.dumm = 0
    print cont.dumm
Wie erwartet wird eine Exception geworfen wenn ich versuche die Variable "dumm" zuzuweisen.
Meine Frage(n): Ist da ein Fehler drin oder geht das irgendwie "eleganter" und/oder kürzer?

MfG,
Uwe
DasIch
User
Beiträge: 2452
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Samstag 4. April 2009, 13:58

Code: Alles auswählen

In [20]: class Foo(object):
   ....:     __slots__ = ('foo', 'bar')
   ....:     def __init__(self, foo, bar):
   ....:         self.foo, self.bar = foo, bar

In [21]: Foo(1, 2).baz = 3
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
...
AttributeError: 'Foo' object has no attribute 'baz'

In [22]: Foo(1, 2).foo
Out[22]: 1
Pumeluk2
User
Beiträge: 26
Registriert: Samstag 24. März 2007, 11:24

Samstag 4. April 2009, 14:15

Danke, aber *mmhh*,

entweder versteh ich das nicht, oder mein Python (2.5.irgendwas) spielt da nicht mit.

Wenn ich:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf-8

class Container(object):

    __slots__ = ('name')

    def __init__(self):
        self.name = ''

if __name__ == '__main__':
    cont = Container()
    cont.name = 'Hallo'
    print cont.name
    cont.test = '123'
    print cont.test
eingebe, dann läuft das Programm ohne Fehler durch *???*
BlackJack

Samstag 4. April 2009, 14:16

@Pumeluk2: Darf man fragen warum Du das machen willst?
Pumeluk2
User
Beiträge: 26
Registriert: Samstag 24. März 2007, 11:24

Samstag 4. April 2009, 14:24

Ist ja fast ein Chat hier :D
BlackJack hat geschrieben:@Pumeluk2: Darf man fragen warum Du das machen willst?
Weil es geht :twisted:

Nein ernsthaft: Dieser Datencontainer soll schon mehr Variablen enthalten als nur "name". Es könnten so 30 bis 40 werden. Und da ich als Tastaturlegastheniker mich des öfteren vertippe, möchte ich so auf meine eigenen Tippfehler hingewesen werden. Also wenn ich statt cont.name = 'hallo" zu tippen, cont.nme = 'hallo' eingebe, bemerke ich den Fehler sofort und nicht erst zufällig Jahre später ;)
DasIch
User
Beiträge: 2452
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Samstag 4. April 2009, 14:44

Pumeluk2 hat geschrieben:eingebe, dann läuft das Programm ohne Fehler durch *???*
('name') ist kein tuple sondern ein string, du musst ('name', ) verwenden dann gehts.
BlackJack

Samstag 4. April 2009, 15:18

@Pumeluk2: So etwas sollte man eigentlich eher mit Unittests prüfen und nicht durch solche Einschränkungen.
Pumeluk2
User
Beiträge: 26
Registriert: Samstag 24. März 2007, 11:24

Samstag 4. April 2009, 15:59

DasIch hat geschrieben:
Pumeluk2 hat geschrieben:eingebe, dann läuft das Programm ohne Fehler durch *???*
('name') ist kein tuple sondern ein string, du musst ('name', ) verwenden dann gehts.
*???* - das habe ich irgendwie nicht verstanden ...

@BlackJack: Schon klar, aber wie ich schon schrieb "spiele" ich mit Python. D.h. dadurch das ich solche Sachen ausprobiere lerne ich mehr über Python. Die Sache mit den "magischen" Prozeduren war mir bisher immer ein Buch mit sieben Siegeln, nun habe ich darüber viele interessante Seiten und Tipps und Tricks dazu gefunden. Das ist letztendlich der eigentliche Sinn und Zweck.
DasIch
User
Beiträge: 2452
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Samstag 4. April 2009, 16:03

Pumeluk2 hat geschrieben:
DasIch hat geschrieben:
Pumeluk2 hat geschrieben:eingebe, dann läuft das Programm ohne Fehler durch *???*
('name') ist kein tuple sondern ein string, du musst ('name', ) verwenden dann gehts.
*???* - das habe ich irgendwie nicht verstanden ...
Vielleicht erklärt etwas Code dein Problem:

Code: Alles auswählen

In [53]: map(type, ('foo', ('foo'), ('foo', )))
Out[53]: [<type 'str'>, <type 'str'>, <type 'tuple'>]
Die Sache mit den "magischen" Prozeduren war mir bisher immer ein Buch mit sieben Siegeln, nun habe ich darüber viele interessante Seiten und Tipps und Tricks dazu gefunden.
Das sind Methoden ;) Die Doku erklärt dass recht gut.
BlackJack

Samstag 4. April 2009, 17:11

@Pumelik2: Eine weitere Möglichkeit wäre es `pylint` zu verwenden. Das warnt vor Attributen, die nicht in der `__init__()` erzeugt wurden.
Antworten