Seite 1 von 1
Properties definieren
Verfasst: Freitag 6. November 2015, 00:28
von NoPy
Hi, ich bin letztlich immer noch bei meiner Excel- Tabelle. Ich möchte gern so etwas abbilden:
Code: Alles auswählen
my_exl = MyExl('Test.xlsx','Tabelle1')
for spalte in ('A','B','C'):
for zeile in (1,2,3):
if my_exl[Spalte,Zeile]==123:
my_exl[Spalte,Zeile] = 321
Wie muss ich die properties dekorieren, dass es so geht?
Folgendes klappt jedenfalls nicht:
Code: Alles auswählen
class ProTest:
def __init__(self):
self.Wert=[[0,1,2,3,4],[5,6,7,8,9],[10,11,12,13,14],[15,16,17,18,19]]
def get(self,Adresse):
Spalte,Zeile = Adresse
return self.Wert[Zeile][Spalte]
def set(self,Adresse,Wert):
Spalte,Zeile = Adresse
self.Wert[Zeile][Spalte] = Wert
Zelle = property(get, set, None, "I'm the 'x' property.")
Folgendes läuft fehlerfrei
Aber egal, welches von Folgendem,
Code: Alles auswählen
print p.Zelle[3,1]
print p.Zelle[3][1]
print p.Zelle[(3,1)]
es kommt immer die Fehlermeldung
TypeError: get() takes exactly 2 arguments (1 given)
Wie muss ich solch ein property deklarieren/dekorieren - was auch immer?
Re: Properties definieren
Verfasst: Freitag 6. November 2015, 00:32
von Sirius3
@NoPy: Du willst hier kein Property, sondern Indexzugriff per __getitem__ und __setitem__.
Re: Properties definieren
Verfasst: Freitag 6. November 2015, 00:43
von NoPy
Vielen Dank
Code: Alles auswählen
class ProTest:
def __init__(self):
self.Wert=[[0,1,2,3,4],[5,6,7,8,9],[10,11,12,13,14],[15,16,17,18,19]]
def __getitem__(self, Adresse):
Spalte,Zeile = Adresse
return self.Wert[Zeile][Spalte]
def __setitem__(self, Adresse, wert):
Spalte,Zeile = Adresse
self.Wert[Zeile][Spalte] = wert
scheint mein akutes Problem tatsächlich erst einmal zu lösen.
Der Aufruf wäre dann
Aber was mache ich, wenn ich wirklich ein property haben will?
Also
Code: Alles auswählen
print p.MeinErstesProperty[3,1]
print p.MeinZweitesProperty[3,1]
Re: Properties definieren
Verfasst: Freitag 6. November 2015, 00:53
von Sirius3
@NoPy: die Properties liefern dann Objekte, die Indexzugriff erlauben.
Re: Properties definieren
Verfasst: Freitag 6. November 2015, 00:54
von pillmuncher
@NoPy: Properties funktionieren in Python 2.x nur auf New Style Classes. Dazu muss eine Klasse von object erben, andernfalls bleibt sie eine Old Style Class.
Hier eine magische Lösung deines Problems:
Code: Alles auswählen
class Sheet(object):
def __init__(self):
self._values = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]
]
@property
class cell(object):
def __init__(self, sheet):
self._sheet = sheet
def __getitem__(self, key):
col, row = key
return self._sheet._values[col][row]
def __setitem__(self, key, value):
col, row = key
self._sheet._values[col][row] = value
s = Sheet()
print s.cell[2, 3]
Ergebnis:
Re: Properties definieren
Verfasst: Freitag 6. November 2015, 01:15
von NoPy
Vielen Dank. Aber so vollständig habe ich es nicht verstanden.
An welcher Stelle wird die Verbindung hergestellt zwischen "cell" und "_values"?
Eigentlich kann ich mir das nur erklären, indem beim __init__ auch noch alle "Unterklassen" initialisiert werden und dabei als Parameter implizit selfals Parameter übergeben bekommen hat.
also ein impliziter Aufruf von cell(self)
Habe ich das richtig interpretiert?
Und wenn das so ist, inwieweit hat @property damit etwas zu tun?
Re: Properties definieren
Verfasst: Freitag 6. November 2015, 01:35
von pillmuncher
@NoPy: Naja, halb richtig interpretiert. Es hat nichts mit Unterklassen zu tun. Es würde auch so funktionieren:
Code: Alles auswählen
class Cell(object):
def __init__(self, sheet):
self._sheet = sheet
def __getitem__(self, key):
col, row = key
return self._sheet._values[col][row]
def __setitem__(self, key, value):
col, row = key
self._sheet._values[col][row] = value
class Sheet(object):
def __init__(self):
self._values = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]
]
cell = property(Cell)
Cell ist eine Klasse. Klassen sind aufrufbar. Wenn ich eine Klasse aufrufe, wird ein neues Exemplar der Klasse erzeugt und die __init__ Methode aufgerufen. Der erste Parameter dieses Methodenaufrufs wird an die neue Instanz gebunden. Per Konvention wird dazu der Name self verwendet. Wir haben also sowas:
Code: Alles auswählen
>>> class Foo:
... def __init__(self):
... print 'in Foo.__init__'
...
>>> Foo()
in Foo.__init__
<__main__.Foo instance at 0x7f834766e098>
>>> class Bar:
... def __init__(self, x):
... print 'in Bar.__init__ got', x
...
>>> Bar(123)
in Bar.__init__ got 123
<__main__.Bar instance at 0x7f834766e128>
Im zweiten Beispiel rufe ich Bar mit einem Argument auf. In __init__ werden aber zwei Parameter gebunden: self an das Bar-Exemplar und x an das explizit übergebene Argument.
Properties kann man prinzipiell mit jedem aufrufbaren Ding erzeugen. Beim Propertyzugriff wird dieses aufrufbare Ding aufgerufen und ihm eine Referenz auf das Objekt mitgegeben, dessen Property es ist. Falls das aufrufbare Ding eine Klasse ist, bekommt dessen __init__ als erstes - implizites - Argument das Property-Exemplar (gebunden an self) und als zweites Argument das Exemplar der Klasse, deren Property es ist. Ja, es ist etwas magisch.
Re: Properties definieren
Verfasst: Freitag 6. November 2015, 09:20
von NoPy
Also habe ich es im Grunde richtig verstanden bis auf im Wesentlichen folgende Details:
- Die Subklasse wird nicht instanziiert, wenn die Klasse instanziiert wird, sondern erst bei Aufruf
- Wenn sie instanziiert wird, bekommt sie automatisch als zweiten Parameter einen Verweis auf den parent mit