Seite 1 von 1

Klasse nur mit "erlaubten" Variablen ...

Verfasst: Samstag 4. April 2009, 13:49
von Pumeluk2
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

Verfasst: Samstag 4. April 2009, 13:58
von DasIch

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

Verfasst: Samstag 4. April 2009, 14:15
von Pumeluk2
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 *???*

Verfasst: Samstag 4. April 2009, 14:16
von BlackJack
@Pumeluk2: Darf man fragen warum Du das machen willst?

Verfasst: Samstag 4. April 2009, 14:24
von Pumeluk2
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 ;)

Verfasst: Samstag 4. April 2009, 14:44
von DasIch
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.

Verfasst: Samstag 4. April 2009, 15:18
von BlackJack
@Pumeluk2: So etwas sollte man eigentlich eher mit Unittests prüfen und nicht durch solche Einschränkungen.

Verfasst: Samstag 4. April 2009, 15:59
von Pumeluk2
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.

Verfasst: Samstag 4. April 2009, 16:03
von DasIch
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.

Verfasst: Samstag 4. April 2009, 17:11
von BlackJack
@Pumelik2: Eine weitere Möglichkeit wäre es `pylint` zu verwenden. Das warnt vor Attributen, die nicht in der `__init__()` erzeugt wurden.