Seite 1 von 1
Unvorhersehbare namedtuple-Funktion
Verfasst: Samstag 31. Mai 2014, 22:52
von Goswin
Warum verhält sich namedtuple je nach Zusammenhang so verschieden?
Im folgenden Programmstück funktioniert alles wie vorgeschrieben und auch erwartet: der Abruf über Namen als auch über Indices, die wiederholte Wertzuweisung hingegen ist verboten:
Code: Alles auswählen
from collections import namedtuple
class Kl():
def __init__(self):
self.pkt = namedtuple('Punkt','x y')
self.pkt = self.pkt(10,20)
##########################################
kl = Kl()
print(kl.pkt)
print(kl.pkt.y)
print(kl.pkt[1])
kl.pkt.y = 30 #AttributeError: can't set attribute
Hier aber funktioniert erstaunlicherweise (und angenehmerweise) sogar die wiederholte Wertzuweisung (für Tupel eigentlich verboten), aber dafür funktioniert der Abruf über Indices nicht mehr:
Code: Alles auswählen
from collections import namedtuple
class Kl():
def __init__(self):
self.pkt = namedtuple('Punkt','x y')
(self.pkt.x, self.pkt.y) = (10,20)
##########################################
kl = Kl()
print(kl.pkt)
print(kl.pkt.y)
kl.pkt.y = 30
print(kl.pkt.y)
print(kl.pkt[1]) #TypeError: 'type' object is not subscriptable
Mit dieser zweiten Alternative wäre ich ja eigentlich ganz zufrieden; was mich aber trotzdem verärgert ist, dass sich Python so unvorhersehbar verhält. Gibt es dafür eine Erklärung?
Re: Unvorhersehbare namedtuple-Funktion
Verfasst: Samstag 31. Mai 2014, 23:22
von BlackJack
@Goswin: Was hier sehr verwirrend ist, ist dass Du den gleichen Namen beziehungsweise das gleiche Attribut an sehr verschiedene Dinge bindest, nämlich sowohl an den *Datentyp* der mit `namedtuple()` erstellt wird, als auch an ein Exemplar. Und an den *Datentyp* kann man beliebige Attribute binden, aber natürlich nicht per Index zugreifen. Das ist irgendwie nicht weiter verwunderlich.
Warum bindest Du den *Datentyp* überhaupt an das `Kl`-Exemplar? Warum erstellst Du da jedes mal wenn ein `Kl`-Exemplar erstellt wird auch immer einen neuen Datentyp — der aber immer die gleichen Eigenschaften hat? Das macht keinen Sinn.
Der Quelltext sollte eigentlich so aussehen:
Code: Alles auswählen
Punkt = namedtuple('Punkt', 'x y')
class Klasse(object):
def __init__(self):
self.punkt = Punkt(10, 20)
Re: Unvorhersehbare namedtuple-Funktion
Verfasst: Sonntag 1. Juni 2014, 00:14
von Goswin
BlackJack hat geschrieben:Warum erstellst Du da jedes mal wenn ein `Kl`-Exemplar erstellt wird auch immer einen neuen Datentyp — der aber immer die gleichen Eigenschaften hat?
Ich habe das Beispiel aus seinem Zusammenhang gelöst, um unerwünschte Nebeneffekte zu vermeiden. Die Exemplare der Klasse Kl welche ich benutze (heißt nicht wirklich Kl) haben noch viele andere Attribute und mehrere Methoden - und zusätzlich eben auch noch Attribute vom Typ 'Punkt'.
Meinst du vielleicht, dass die Anweisung
außerhalb jeglicher Klassendefinition "mutterseelenallein" im Modul stehen soll? Ist das die vorgesehene Anwendungsweise? Vielleicht habe ich nur die angelernte (und möglicherweise "suboptimale") Gewohnheit, solches in objektorientierter Programmierung zu vermeiden.
Re: Unvorhersehbare namedtuple-Funktion
Verfasst: Sonntag 1. Juni 2014, 00:37
von BlackJack
@Goswin: Typen definiert man in der Regel auf Modulebene. Du schreibst doch normalerweise ``class``-Anweisungen auch nicht *in* Methoden sondern auf Modulebene. Und ein `namedtupel()`-Aufruf macht das selbe wie eine ``class``-Anweisung: Eine Klasse erstellen die eine Unterklasse von `tuple` ist. Du bringst hier Klassen, also Datentypen, und Exemplare von diesen Typen durcheinander. Beides sind in Python Werte, also Objekte, die man benennen, umbenennen, als Argumente übergeben, oder halt auch als Rückgabewert von einem Aufruf bekommen kann.
Code: Alles auswählen
In [7]: Punkt = collections.namedtuple('Punkt', 'x y')
In [8]: Punkt
Out[8]: __main__.Punkt
In [9]: punkt = Punkt(42, 23)
In [10]: punkt
Out[10]: Punkt(x=42, y=23)
In [11]: type(Punkt)
Out[11]: type
In [12]: type(punkt)
Out[12]: __main__.Punkt
In [13]: issubclass(Punkt, tuple)
Out[13]: True
In [14]: issubclass(punkt, tuple)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-e1050bd6d9a5> in <module>()
----> 1 issubclass(punkt, tuple)
TypeError: issubclass() arg 1 must be a class
Re: Unvorhersehbare namedtuple-Funktion
Verfasst: Sonntag 1. Juni 2014, 19:45
von Goswin
BlackJack hat geschrieben:Typen definiert man in der Regel auf Modulebene. [...] Und ein `namedtupel()`-Aufruf macht das selbe wie eine ``class``-Anweisung.
Tja, das sehe ich
jetzt auch so. Bisher hatte ich immer (da namedtupel eine Fuktion ist) das namedtuple wie eine Methode und nicht wie eine Klassendefinition behandelt. Alles klar, danke!
Re: Unvorhersehbare namedtuple-Funktion
Verfasst: Sonntag 1. Juni 2014, 23:08
von snafu
``namedtuple`` würde ich als eine Fabrikfunktion zum Erstellen einer von ``tuple`` abgeleiteten Klasse ansehen. Wichtig ist ja nur das Ergebnis (also der Rückgabewert), denn nur damit wird im weiteren Verlauf gearbeitet. Wie dies zustande kam, ist so gesehen zweitrangig.