Ich frage mich, ob Python so etwas wie die Funktion für anonyme C # -Klassen hat. Zur Verdeutlichung hier ein Beispiel für ein C # -Schnipsel:
var foo = new { x = 1, y = 2 };
var bar = new { y = 2, x = 1 };
foo.Equals(bar); // "true"
In Python würde ich mir so etwas vorstellen:
foo = record(x = 1, y = 2)
bar = record(y = 2, x = 1)
foo == bar # true
Die spezielle Anforderung besteht darin, ein Objekt mit bestimmten Feldern im Ausdruckskontext erstellen zu können (z. B. in Lambdas und anderen Orten verwendbar, an denen Anweisungen nicht zulässig sind), ohne zusätzliche externe Deklarationen und über das normale Mitglied namentlich auf einzelne Komponenten zugreifen zu können Zugriffssyntax foo.bar
. Das erstellte Objekt sollte auch einen strukturellen Vergleich nach Komponentennamen implementieren (nicht nach Position, wie dies bei Tupeln der Fall ist).
Insbesondere: Tupel nicht, weil ihre Komponenten nicht benannt sind; Klassen nicht, weil sie eine Deklaration erfordern; dicts ist es nicht, weil sie unerwünschte foo["bar"]
Syntax haben, um auf Komponenten zuzugreifen.
namedtuple ist es nicht, da es auch dann noch einen Namen erfordert, wenn Sie den Typ inline definieren und der Vergleich positionsbasiert und nicht namensbasiert ist. Speziell:
def foo(): return namedtuple("Foo", "x y")(x = 1, y = 2)
def bar(): return namedtuple("Foo", "y x")(x = 1, y = 2)
foo() == bar() # False because fields are compared in order, and not by name
# True would be desired instead
Ich weiß, wie man so etwas bei Bedarf in Python schreibt. Aber ich würde gerne wissen, ob es so etwas in der Python-Standardbibliothek oder in beliebten Bibliotheken von Drittanbietern gibt.
[BEARBEITEN]
Aus diesem Grund gibt es hier eine Lösung mit einem Ausdruck, die zwei sehr informative Antworten von Ken und Alanlcode kombiniert und strukturelle Gleichheit ohne zusätzliche externe Erklärungen ergibt:
type("", (), { \
"__init__": (lambda self, **kwargs: self.__dict__.update(kwargs)), \
"__eq__": (lambda self, other: self.__dict__ == other.__dict__) } \
)(x = 1, y = 2)
Technisch erfüllt es alle Anforderungen der Frage, aber ich hoffe aufrichtig, dass niemand es jemals benutzt (ich werde es definitiv nicht tun).
namedtuple
Absicht ziemlich nahe zu kommen scheint .Antworten:
Der pythonische Weg wäre, a zu verwenden
dict
:>>> foo = dict(x=1, y=2) >>> bar = dict(y=2, x=1) >>> foo == bar True
Erfüllt alle Ihre Anforderungen, außer dass Sie noch tun müssen,
foo['x']
anstattfoo.x
.Wenn dies ein Problem ist, können Sie leicht eine Klasse definieren wie:
class Bunch(object): def __init__(self, **kwds): self.__dict__.update(kwds) def __eq__(self, other): return self.__dict__ == other.__dict__
Oder eine schöne und kurze
class Bunch(dict): __getattr__, __setattr__ = dict.get, dict.__setitem__
(aber beachte, dass dieser zweite Probleme hat, wie Alex in seinem Kommentar betont!)
quelle
namedtuple
, dass es den größten Teil des syntaktischen Zuckers gibt, den ich will.__getattribute__ = dict.get
? Hässlich, ja, aber hat es immer noch Probleme?Es sieht so aus, als hätte Python 3.3 genau dieses Ding in Form einer
types.SimpleNamespace
Klasse hinzugefügt .quelle
1) Siehe http://uszla.me.uk/space/blog/2008/11/06 . Mit der
type
integrierten Funktion können Sie ein anonymes Objekt mit leicht hässlicher Syntax erstellen :anon_object_2 = type("", (), {})()
Dabei ist der dritte Parameter das Diktat, das die Felder Ihres Objekts enthält.
foo = type("", (), dict(y=1))() foo.y == 1
2) Eine weitere Variante wird von Peter Norvig unter http://norvig.com/python-iaq.html vorgeschlagen . Es ähnelt auch der Antwort von Ken.
class Struct: def __init__(self, **entries): self.__dict__.update(entries) >>> options = Struct(answer=42, linelen = 80, font='courier') >>> options.answer 42
Der Vorteil dieser Methode besteht darin, dass Sie die Gleichheit nach Inhalten des Diktats implementieren können, die die erste Option nicht hat.
quelle
Das Typformular (...) erfüllt die strukturelle Vergleichsanforderung nicht (ohne wirklich hässlich zu werden). Das Diktatformular (...) erfüllt nicht die Attributzugriffsanforderungen.
Das Attribut scheint irgendwo in die Mitte zu fallen:
class attrdict(dict): def __init__(self, *args, **kwargs): dict.__init__(self, *args, **kwargs) self.__dict__ = self a = attrdict(x=1, y=2) b = attrdict(y=2, x=1) print a.x, a.y print b.x, b.y print a == b
Aber es bedeutet, eine spezielle Klasse zu definieren.
OK, ich habe gerade das Update der Frage bemerkt. Ich werde nur bemerken, dass Sie
dict
für den Basisparameter angeben können und nur dann den Konstruktor angeben müssen (im Ausdruck icky type). Ich bevorzuge attrdict. :-)quelle
__init__
Anruf nicht so aussehensuper(attrdict, self).__init__(*args, **kwargs)
?Ich erinnere mich nicht ohne weiteres, ob es eine integrierte Funktion gibt, aber das Schreiben selbst ist kürzer als das Eingeben Ihrer Frage. :-)
class record(object): def __init__(self, **kwargs): self.__dict__ = kwargs def __eq__(self, r2): return self.__dict__ == r2.__dict__ def __ne__(self, r2): return self.__dict__ != r2.__dict__ foo = record(x=1, y=2) bar = record(y=2, x=1) foo == bar # => true
quelle
__neq__
wirklich gebraucht? Wird die Standarddefinition nichtnot __eq__
automatisch bereitgestellt?__neq__
sollte sein__ne__
, und nein, es wird nicht automatisch bereitgestellt.Wenn Sie möchten, dass die Instanz ebenfalls anonym ist (indem Sie das Objekt direkt in einem Ausdruck verwenden), müssen Sie den Typausdruck verwenden. In vielen Fällen ist die Instanz jedoch nicht anonym, sondern einer Variablen zugeordnet. Dieser Fall kann in Python in angemessener Weise mit Metaklassen oder Dekoratoren behandelt werden.
Ein Beispiel mit Dekorateur:
def anonymous(cls): return cls() @anonymous class foo: x = 42 def bar(self): return self.x
In diesem Fall bewirkt der Dekorator, dass die Klasse
foo
instanziiert undfoo
anstelle der Klasse selbst in die Variable eingefügt wird. Auf die Klasse selbst kann von keinem Namespace aus zugegriffen werden, obwohl sie einen Namen hat:>>> foo <__main__.foo instance at 0x7fd2938d8320> >>> foo.bar() 42
Ein weiteres Merkmal in Python, das für viele Anwendungsfälle geeignet ist, ist, dass es legal ist, Klassen lokal zu definieren, was bedeutet, dass sie zu einem lokalen Symbol für diese Funktion werden, was wiederum ein gewisses Maß an Anonymität verleiht.
quelle
Zitiert von dieser Seite :
class Struct: def __init__(self, **entries): self.__dict__.update(entries) def __eq__(self, other): return self.__dict__ == other.__dict__ def __ne__(self, other): return self.__dict__ != other.__dict__ options = Struct(answer=42, linelen = 80, font='courier') options.answer >>> 42 options.answer = 'plastics' vars(options) >>> {'answer': 'plastics', 'font': 'courier', 'linelen': 80}
quelle
Wie oben gezeigt, bekomme ich dafür eine gute Intelligenz von pycharm und ich liebe diese Lösung ...
>>> def anonymous(cls): ... return cls() >>> class fooo: ... @anonymous ... class c: ... D=10 >>> fooo.c.D 10
quelle