Verwenden von property () für Klassenmethoden

173

Ich habe eine Klasse mit zwei Klassenmethoden (unter Verwendung der Funktion classmethod ()) zum Abrufen und Festlegen einer im Wesentlichen statischen Variablen. Ich habe versucht, die Eigenschaft property () mit diesen zu verwenden, aber es führt zu einem Fehler. Ich konnte den Fehler im Interpreter wie folgt reproduzieren:

class Foo(object):
    _var = 5
    @classmethod
    def getvar(cls):
        return cls._var
    @classmethod
    def setvar(cls, value):
        cls._var = value
    var = property(getvar, setvar)

Ich kann die Klassenmethoden demonstrieren, aber sie funktionieren nicht als Eigenschaften:

>>> f = Foo()
>>> f.getvar()
5
>>> f.setvar(4)
>>> f.getvar()
4
>>> f.var
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable
>>> f.var=5
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'classmethod' object is not callable

Ist es möglich, die Eigenschaft property () mit mit Klassenmethoden dekorierten Funktionen zu verwenden?

Mark Roddy
quelle

Antworten:

90

Eine Eigenschaft wird für eine Klasse erstellt, wirkt sich jedoch auf eine Instanz aus. Wenn Sie also eine classmethod-Eigenschaft möchten, erstellen Sie die Eigenschaft in der Metaklasse.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

Da Sie jedoch ohnehin eine Metaklasse verwenden, ist es besser zu lesen, wenn Sie nur die Klassenmethoden dort hinein verschieben.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

oder unter Verwendung der Python 3- metaclass=...Syntax und der außerhalb des fooKlassenkörpers definierten Metaklasse und der Metaklasse, die für die Festlegung des Anfangswertes verantwortlich ist _var:

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
A. Coady
quelle
1
Dies scheint für mich in Python 3.2 nicht zu funktionieren. Wenn ich foo .__ metaclass __. Var = property (foo.getvar.im_func, foo.setvar.im_func) in foo .__ metaclass __. Var = property (foo.getvar .__ func__, foo.setvar .__ func__) ändere, erhalte ich "AttributeError: type Objekt 'foo' hat kein Attribut 'var' ", wenn" foo.var "ausgeführt wird.
Michael Kelley
SIGH- Doppelkorrektur: Dies funktioniert in Python 2.7, jedoch nicht in Python 3.2.
Michael Kelley
@ MichaelKelley - Das liegt daran, dass sich die Syntax für Metaklassen in Python 3.x
Mac
1
Ich bin mir nicht ganz sicher zu verstehen, wie Python 3.x das dann schreiben würde.
SylvainD
8
@Josay: Sie müssen zuerst die Metaklasse definieren und dann die Klasse mit der neuen class Foo(metaclass=...)Syntax definieren.
Kevin
69

Beim Lesen der Python 2.2- Versionshinweise finde ich Folgendes.

Die get-Methode [einer Eigenschaft] wird nicht aufgerufen, wenn auf die Eigenschaft als Klassenattribut (Cx) anstatt als Instanzattribut (C (). X) zugegriffen wird. Wenn Sie die Operation __get__ für Eigenschaften überschreiben möchten, wenn sie als Klassenattribut verwendet wird, können Sie die Eigenschaft __get__ in eine Unterklasse umwandeln - es handelt sich um einen Typ neuen Stils - oder einen Deskriptortyp von Grund auf neu definieren, indem Sie einen neuen erstellen -style-Klasse, die die Methoden __get__, __set__ und __delete__ definiert.

HINWEIS: Die folgende Methode funktioniert nicht für Setter, sondern nur für Getter.

Daher glaube ich, dass die vorgeschriebene Lösung darin besteht, eine ClassProperty als Unterklasse von Eigenschaften zu erstellen.

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

Die Setter funktionieren jedoch nicht wirklich:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var unverändert ist, haben Sie die Eigenschaft einfach mit einem neuen Wert überschrieben.

Sie können auch ClassPropertyals Dekorateur verwenden:

class foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5
Jason R. Coombs
quelle
20
Ich glaube nicht, dass der Setter-Teil der ClassProperty tatsächlich wie beschrieben funktioniert: Während die Behauptungen des Beispiels alle bestehen, ist am Ende foo._var == 4 (nicht 3, wie impliziert). Durch das Festlegen der Eigenschaft wird die Eigenschaft selbst blockiert. Als Klasseneigenschaften auf Python-Dev besprochen wurden , wurde darauf hingewiesen, dass Getter zwar trivial sind, Setter aber ohne Metaklasse schwierig (unmöglich?) Sind
Gabriel Grant
4
@ Gabriel Ganz richtig. Ich kann nicht glauben, dass zwei Jahre lang niemand darauf hingewiesen hat.
Agf
Ich bin mir auch nicht sicher, warum Sie hier nicht einfach self.fget(owner)die Notwendigkeit verwenden und entfernen müssen, überhaupt eine zu verwenden @classmethod? (das ist , was classmethod ist , zu übersetzen , .__get__(instance, owner)(*args, **kwargs)um function(owner, *args, **kwargs)Anrufe über einen Vermittler, Eigenschaften haben die Vermittler nicht brauchen).
Martijn Pieters
Ihrer Demonstration fehlt entweder im Getter oder im Setter eine tatsächliche Transformation, die genau demonstrieren würde, dass Ihre foo.var = 3Zuweisung die Eigenschaft nicht tatsächlich durchläuft , sondern stattdessen einfach das Eigenschaftsobjekt foodurch eine Ganzzahl ersetzt hat. Wenn Sie assert isinstance(foo.__dict__['var'], ClassProperty)zwischen Ihren Zusicherungen Aufrufe hinzugefügt haben, wird dieser nach der foo.var = 3Ausführung fehlschlagen .
Martijn Pieters
1
Python - Klassen nicht unterstützen Descriptor verbindlich Einstellung auf der Klasse selbst , nur auf immer (so instance.attr, instance.attr = valueund del instance.attrwird alle bind der Deskriptor gefunden auf type(instance), aber während classobj.attrbindet, classobj.attr = valueund del classobj.attrsie nicht und stattdessen ersetzen oder das Descriptor - Objekt selbst löschen). Sie benötigen eine Metaklasse, um das Festlegen und Löschen zu unterstützen (das Klassenobjekt wird zur Instanz und die Metaklasse zum Typ).
Martijn Pieters
56

Ich hoffe, dieser @classpropertyabsolut einfache, schreibgeschützte Dekorateur würde jemandem helfen, der nach Klasseneigenschaften sucht.

class classproperty(object):

    def __init__(self, fget):
        self.fget = fget

    def __get__(self, owner_self, owner_cls):
        return self.fget(owner_cls)

class C(object):

    @classproperty
    def x(cls):
        return 1

assert C.x == 1
assert C().x == 1
Denis Ryzhkov
quelle
2
Funktioniert das mit Unterklassen? (Kann eine Unterklasse Klasseneigenschaften überschreiben?)
zakdances
1
Umm ja? class D(C): x = 2; assert D.x == 2
Thetheor
Ich wünschte, dies würde funktionieren, wenn ich es in .formatwie "{x}".format(**dict(self.__class__.__dict__, **self.__dict__))
folgt verwende
@ Nathan Nicht nur ... wenn Sie es einstellen, überschreiben Sie jeden xZugriff durch 10. Ich mag diesen Ansatz, weil er ordentlich und einfach ist, aber wie ein
Michele d'Amico
Einfach zu beheben: Fügen Sie ein hinzu __set__, das ein erhöht ValueError, um ein Überschreiben zu verhindern.
Kiran Jonnalagadda
30

Ist es möglich, die Eigenschaft property () mit mit Klassenmethoden dekorierten Funktionen zu verwenden?

Nein.

Eine Klassenmethode ist jedoch einfach eine gebundene Methode (eine Teilfunktion) für eine Klasse, auf die über Instanzen dieser Klasse zugegriffen werden kann.

Da die Instanz eine Funktion der Klasse ist und Sie die Klasse von der Instanz ableiten können, können Sie von einer Klasseneigenschaft das gewünschte Verhalten erhalten property:

class Example(object):
    _class_property = None
    @property
    def class_property(self):
        return self._class_property
    @class_property.setter
    def class_property(self, value):
        type(self)._class_property = value
    @class_property.deleter
    def class_property(self):
        del type(self)._class_property

Dieser Code kann zum Testen verwendet werden - er sollte ohne Fehler bestehen:

ex1 = Example()
ex2 = Example()
ex1.class_property = None
ex2.class_property = 'Example'
assert ex1.class_property is ex2.class_property
del ex2.class_property
assert not hasattr(ex1, 'class_property')

Und beachten Sie, dass wir überhaupt keine Metaklassen benötigten - und Sie sowieso nicht direkt über die Instanzen ihrer Klassen auf eine Metaklasse zugreifen.

einen @classpropertyDekorateur schreiben

Sie können einen classpropertyDekorator in nur wenigen Codezeilen durch Unterklassen erstellen property(es ist in C implementiert, aber Sie können hier gleichwertiges Python sehen ):

class classproperty(property):
    def __get__(self, obj, objtype=None):
        return super(classproperty, self).__get__(objtype)
    def __set__(self, obj, value):
        super(classproperty, self).__set__(type(obj), value)
    def __delete__(self, obj):
        super(classproperty, self).__delete__(type(obj))

Behandeln Sie den Dekorateur dann so, als wäre es eine Klassenmethode kombiniert mit einer Eigenschaft:

class Foo(object):
    _bar = 5
    @classproperty
    def bar(cls):
        """this is the bar attribute - each subclass of Foo gets its own.
        Lookups should follow the method resolution order.
        """
        return cls._bar
    @bar.setter
    def bar(cls, value):
        cls._bar = value
    @bar.deleter
    def bar(cls):
        del cls._bar

Und dieser Code sollte fehlerfrei funktionieren:

def main():
    f = Foo()
    print(f.bar)
    f.bar = 4
    print(f.bar)
    del f.bar
    try:
        f.bar
    except AttributeError:
        pass
    else:
        raise RuntimeError('f.bar must have worked - inconceivable!')
    help(f)  # includes the Foo.bar help.
    f.bar = 5

    class Bar(Foo):
        "a subclass of Foo, nothing more"
    help(Bar) # includes the Foo.bar help!
    b = Bar()
    b.bar = 'baz'
    print(b.bar) # prints baz
    del b.bar
    print(b.bar) # prints 5 - looked up from Foo!

    
if __name__ == '__main__':
    main()

Aber ich bin mir nicht sicher, wie gut das beraten wäre. Eine alte Mailingliste Artikel schlägt vor , es nicht funktionieren sollte.

Damit die Eigenschaft für die Klasse funktioniert:

Der Nachteil des oben Gesagten ist, dass auf die "Klasseneigenschaft" von der Klasse aus nicht zugegriffen werden kann, da sie einfach den Datendeskriptor aus der Klasse überschreiben würde __dict__ .

Wir können dies jedoch mit einer in der Metaklasse definierten Eigenschaft überschreiben __dict__. Beispielsweise:

class MetaWithFooClassProperty(type):
    @property
    def foo(cls):
        """The foo property is a function of the class -
        in this case, the trivial case of the identity function.
        """
        return cls

Und dann könnte eine Klasseninstanz der Metaklasse eine Eigenschaft haben, die nach dem bereits in den vorherigen Abschnitten beschriebenen Prinzip auf die Eigenschaft der Klasse zugreift:

class FooClassProperty(metaclass=MetaWithFooClassProperty):
    @property
    def foo(self):
        """access the class's property"""
        return type(self).foo

Und jetzt sehen wir beide die Instanz

>>> FooClassProperty().foo
<class '__main__.FooClassProperty'>

und die Klasse

>>> FooClassProperty.foo
<class '__main__.FooClassProperty'>

Zugriff auf die Klasseneigenschaft haben.

Aaron Hall
quelle
3
Klar, prägnant, gründlich: Dies sollte die akzeptierte Antwort sein.
Pfabri
25

Python 3!

Alte Frage, viele Ansichten, die dringend einen One-True-Python-3-Weg benötigen.

Zum Glück ist es mit dem metaclassKwarg einfach :

class FooProperties(type):

    @property
    def var(cls):
        return cls._var

class Foo(object, metaclass=FooProperties):
    _var = 'FOO!'

Dann, >>> Foo.var

"FOO!"

OJFord
quelle
1
das heißt, es gibt keinen einfachen Ausweg
mehmet
@mehmet Ist das nicht einfach? Fooist eine Instanz seiner Metaklasse und @propertykann für seine Methoden genauso verwendet werden wie für Instanzen von Foo.
OJFord
2
Sie mussten eine andere Klasse für eine Klasse definieren, was der doppelten Komplexität entspricht, vorausgesetzt, die Metaklasse ist nicht wiederverwendbar.
Mehmet
Eine Klassenmethode funktioniert sowohl in der Klasse als auch in der Instanz. Diese Eigenschaft funktioniert nur in der Klasse. Ich glaube nicht, dass darum gebeten wird.
Aaron Hall
1
@AaronHall Wenn das wichtig ist, kann es leicht hinzugefügt werden Foo.__new__. An diesem Punkt kann es sich jedoch lohnen, stattdessen entweder getattribute zu verwenden oder zu hinterfragen, ob das Vorgeben einer Sprachfunktion wirklich der Ansatz ist, den Sie überhaupt verfolgen möchten.
OJFord
16

Es gibt keine vernünftige Möglichkeit, dieses "Klasseneigenschaft" -System in Python zum Laufen zu bringen.

Hier ist ein unvernünftiger Weg, damit es funktioniert. Sie können es mit zunehmender Menge an Metaklassen-Magie nahtloser machen.

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

Der Knotenpunkt des Problems ist, dass Eigenschaften das sind, was Python "Deskriptoren" nennt. Es gibt keine kurze und einfache Möglichkeit zu erklären, wie diese Art der Metaprogrammierung funktioniert, daher muss ich Sie auf das Deskriptor-Howto verweisen .

Sie müssen diese Art von Dingen nur verstehen, wenn Sie ein ziemlich fortgeschrittenes Framework implementieren. Wie eine transparente Objektpersistenz oder ein RPC-System oder eine Art domänenspezifische Sprache.

In einem Kommentar zu einer früheren Antwort sagen Sie jedoch, dass Sie

Sie müssen ein Attribut so ändern, dass es von allen Instanzen einer Klasse gesehen wird und in dem Bereich, aus dem diese Klassenmethoden aufgerufen werden, nicht auf alle Instanzen der Klasse verweist.

Mir scheint, was Sie wirklich wollen, ist ein Observer- Designmuster.

ddaa
quelle
Ich mag die Idee des Codebeispiels, aber es scheint, als wäre es in der Praxis etwas klobig.
Mark Roddy
Was ich versuche zu erreichen, ist ein ziemlich einfaches Setzen und Abrufen eines einzelnen Attributs, das als Flag verwendet wird, um das Verhalten aller Instanzen zu ändern, sodass ich denke, dass Observer für das, was ich versuche, überfordert wäre. Wenn es mehrere fragliche Attribute gäbe, wäre ich eher geneigt.
Mark Roddy
Es scheint, dass es die einfachste Lösung war, die Funktionen nur öffentlich zu machen und direkt aufzurufen. Ich war neugierig, ob ich etwas falsch gemacht habe oder ob ich versucht habe, es unmöglich zu machen. Entschuldigung für die vielen Kommentare übrigens. 300 Zeichen Limit saugt.
Mark Roddy
Das Schöne am Codebeispiel ist, dass Sie alle klobigen Bits einmal implementieren und dann erben können. Verschieben Sie einfach die _var in die abgeleitete Klasse. Klasse D1 (Foo): _var = 21 Klasse D2 (Foo) _var = "Hallo" D1.var 21 D2.var Hallo
Thomas L Holaday
6

Das Festlegen nur für die Meta-Klasse hilft nicht, wenn Sie über ein instanziiertes Objekt auf die Klasseneigenschaft zugreifen möchten. In diesem Fall müssen Sie auch eine normale Eigenschaft für das Objekt installieren (die an die Klasseneigenschaft gesendet wird). Ich denke, das Folgende ist etwas klarer:

#!/usr/bin/python

class classproperty(property):
    def __get__(self, obj, type_):
        return self.fget.__get__(None, type_)()

    def __set__(self, obj, value):
        cls = type(obj)
        return self.fset.__get__(None, cls)(value)

class A (object):

    _foo = 1

    @classproperty
    @classmethod
    def foo(cls):
        return cls._foo

    @foo.setter
    @classmethod
    def foo(cls, value):
        cls.foo = value

a = A()

print a.foo

b = A()

print b.foo

b.foo = 5

print a.foo

A.foo = 10

print b.foo

print A.foo
Nils Philippsen
quelle
3

Eine halbe Lösung, __set__ für die Klasse, funktioniert immer noch nicht. Die Lösung ist eine benutzerdefinierte Eigenschaftsklasse, die sowohl eine Eigenschaft als auch eine statische Methode implementiert

class ClassProperty(object):
    def __init__(self, fget, fset):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        return self.fget()

    def __set__(self, instance, value):
        self.fset(value)

class Foo(object):
    _bar = 1
    def get_bar():
        print 'getting'
        return Foo._bar

    def set_bar(value):
        print 'setting'
        Foo._bar = value

    bar = ClassProperty(get_bar, set_bar)

f = Foo()
#__get__ works
f.bar
Foo.bar

f.bar = 2
Foo.bar = 3 #__set__ does not
Florian Bösch
quelle
3

Weil ich ein Attribut so ändern muss, dass es von allen Instanzen einer Klasse gesehen wird und in dem Bereich, aus dem diese Klassenmethoden aufgerufen werden, nicht auf alle Instanzen der Klasse verweist.

Haben Sie Zugriff auf mindestens eine Instanz der Klasse? Ich kann mir dann einen Weg vorstellen, es zu tun:

class MyClass (object):
    __var = None

    def _set_var (self, value):
        type (self).__var = value

    def _get_var (self):
        return self.__var

    var = property (_get_var, _set_var)

a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var
John Millikin
quelle
2

Probieren Sie es aus, es erledigt den Job, ohne viel vorhandenen Code ändern / hinzufügen zu müssen.

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

Die propertyFunktion benötigt zwei callableArgumente. Geben Sie ihnen Lambda-Wrapper (die die Instanz als erstes Argument übergeben) und alles ist gut.

Sufian
quelle
Wie Florian Bösch betont, lautet die erforderliche Syntax (für Bibliotheken von Drittanbietern oder Legacy-Code) foo.var.
Thomas L Holaday
2

Hier ist eine Lösung, die sowohl für den Zugriff über die Klasse als auch für den Zugriff über eine Instanz funktionieren sollte, die eine Metaklasse verwendet.

In [1]: class ClassPropertyMeta(type):
   ...:     @property
   ...:     def prop(cls):
   ...:         return cls._prop
   ...:     def __new__(cls, name, parents, dct):
   ...:         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
   ...:         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
   ...:         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
   ...:         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)
   ...:

In [2]: class ClassProperty(object):
   ...:     __metaclass__ = ClassPropertyMeta
   ...:     _prop = 42
   ...:     def __getattr__(self, attr):
   ...:         raise Exception('Never gets called')
   ...:

In [3]: ClassProperty.prop
Out[3]: 42

In [4]: ClassProperty.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-e2e8b423818a> in <module>()
----> 1 ClassProperty.prop = 1

AttributeError: can't set attribute

In [5]: cp = ClassProperty()

In [6]: cp.prop
Out[6]: 42

In [7]: cp.prop = 1
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-7-e8284a3ee950> in <module>()
----> 1 cp.prop = 1

<ipython-input-1-16b7c320d521> in <lambda>(cls, attr, val)
      6         # This makes overriding __getattr__ and __setattr__ in the class impossible, but should be fixable
      7         dct['__getattr__'] = classmethod(lambda cls, attr: getattr(cls, attr))
----> 8         dct['__setattr__'] = classmethod(lambda cls, attr, val: setattr(cls, attr, val))
      9         return super(ClassPropertyMeta, cls).__new__(cls, name, parents, dct)

AttributeError: can't set attribute

Dies funktioniert auch mit einem in der Metaklasse definierten Setter.

Papierkran
quelle
1

Nachdem ich verschiedene Orte durchsucht hatte, fand ich eine Methode, um eine Klasseneigenschaft zu definieren, die mit Python 2 und 3 gültig ist.

from future.utils import with_metaclass

class BuilderMetaClass(type):
    @property
    def load_namespaces(self):
        return (self.__sourcepath__)

class BuilderMixin(with_metaclass(BuilderMetaClass, object)):
    __sourcepath__ = 'sp'        

print(BuilderMixin.load_namespaces)

Hoffe das kann jemandem helfen :)

nicht bekannt gegeben
quelle
1
Wenn Sie diese Methode irgendwo gefunden haben, ist es gut, einen Link anzugeben (siehe Referenzieren von Material, das von anderen geschrieben wurde )
Andrew Myers
-27

Hier ist mein Vorschlag. Verwenden Sie keine Klassenmethoden.

Ernsthaft.

Was ist in diesem Fall der Grund für die Verwendung von Klassenmethoden? Warum nicht ein gewöhnliches Objekt einer gewöhnlichen Klasse haben?


Wenn Sie einfach den Wert ändern möchten, ist eine Eigenschaft nicht wirklich sehr hilfreich, oder? Legen Sie einfach den Attributwert fest und fertig.

Eine Eigenschaft sollte nur verwendet werden, wenn etwas zu verbergen ist - etwas, das sich in einer zukünftigen Implementierung ändern könnte.

Vielleicht ist Ihr Beispiel sehr reduziert, und Sie haben eine höllische Berechnung aufgegeben. Es sieht jedoch nicht so aus, als würde die Immobilie einen erheblichen Mehrwert bieten.

Die von Java beeinflussten "Datenschutz" -Techniken (in Python Attributnamen, die mit _ beginnen) sind nicht wirklich hilfreich. Privat von wem? Der private Punkt ist ein wenig nebulös, wenn Sie die Quelle haben (wie in Python).

Die von Java beeinflussten Getter und Setter im EJB-Stil (in Python häufig als Eigenschaften verwendet) dienen dazu, die primitive Selbstbeobachtung von Java zu erleichtern und die Musterung mit dem statischen Sprachcompiler zu bestehen. All diese Getter und Setter sind in Python nicht so hilfreich.

S.Lott
quelle
14
Weil ich ein Attribut so ändern muss, dass es von allen Instanzen einer Klasse gesehen wird und in dem Bereich, aus dem diese Klassenmethoden aufgerufen werden, nicht auf alle Instanzen der Klasse verweist.
Mark Roddy