2017-11-01 4 views
0

Ich habe eine Klasse mit einer Eigenschaft deleted. Der Benutzer muss die ob.delete() Methode verwenden. Wenn er versucht, ob.deleted = True direkt zu tun, sollte er einen Fehler erhalten.Throw Fehler beim Setzen eines Attributs

class A(ORMBaseClass): 
    deleted = False 

    def delete(self): 
     self.deleted = True 


a = A() 
a.delete() # works 
print(a.delete) # works 
a.deleted = True # must throw exception 
Exception: you cannot directly set deleted 

Ich versuchte es mit __setattr__ Überlastung, aber das wirkt sich ob.delete() auch.

Eigenschaften mit einem ob._deleted privaten Attribute und ob.deleted Eigenschaft sind nicht geeignet, da die Klasse ein ORM-Modell ist und er steht vor der UX Inkonsistenz des session.query(A).filter(A._deleted == True) und a.deleted=True.

Ich weiß Python hat keine vollkommen sichere Möglichkeit, dies zu tun, ich möchte nur stoppen und informieren Sie den Benutzer, der es kausal setzt.

+0

Welche Python verwenden Sie? Ich kann das Problem mit Python-3.6 auf Arch Linux/x86-64 nicht bestätigen – user3159253

+0

das gleiche hier mit 2,7/OsX –

+0

@ user3159253 und Ashish, ich habe schlecht geschrieben, es gibt keinen vorhandenen Fehler. Ich habe den verwirrenden Wortlaut korrigiert. – aitchnyu

Antwort

2

So etwas sollte funktionieren:

class A(object): 
    def __init__(self): 
     self._deleted = False 

    @property 
    def deleted(self): 
     return self._deleted 

    @deleted.setter 
    def deleted(self, value): 
     raise Exception("Can't directly set deleted") 

    def delete(self): 
     self._deleted = True 

Sie get Eigenschaften angeben und Methoden gesetzt und erhöhen Ausnahme, wenn Setter direkt aufgerufen wird. Dies funktioniert auf Python 2.7 und 3.x.

2

Sie könnte dies tun:

def __setattr__(self, name, value): 
    if name == 'deleted': 
     raise AttributeError("you cannot directly set deleted") 
    object.__setattr__(self, name, value) 

Dann in delete, Sie um es direkt gehen durch object.__setattr__(self, 'deleted', True) aufrufen.

Aber Sie sollten wahrscheinlich nichts davon tun. Wenn Sie möchten, dass eine Elementvariable "privat" ist, müssen Sie ihren Namen mit einem Unterstrich beginnen, z. _deleted. Es wird weiterhin beschreibbar sein, aber es ist eine Konvention, die bedeutet, dass "die Variable privat ist, berühre sie nicht".

+0

Verwenden Sie zwei Unterstriche für eine private. Zwei Unterstriche sind mehr als nur eine Konvention, es wird Python zwingen, Namensmangel zu verwenden. Innerhalb der Klasse wird das Attribut "__deleted" sein, aber außerhalb der Klasse "__deleted" wird es nicht existieren. Es wird als "_CLASS__Attribut" bezeichnet. Es ist besonders gut, wenn Sie möchten, dass geerbte Klassen Ihre Attribute nicht durcheinander bringen. –

+0

@ LoïcFaure-Lacroix Eigentlich würde ich nicht empfehlen, zwei Unterstriche für private Variablen als eine allgemeine Regel zu verwenden. Weder "_" noch "__" machen eine wahrhaft private Wahrheit aus. Beide lassen es absolut zugänglich. Letzteres erfordert nur mehr tippen. Ein doppelter Unterstrich ist in einigen Situationen nützlich, die Vererbung beinhalten. Für die einfache "Privatsphäre" muss man sich in Python ohnehin auf Konventionen verlassen, so dass die einfachere Lösung mit einem einzigen Unterstrich fast immer vorgezogen wird. – zvone

0

Hier ist eine bessere Lösung in meiner Beziehung, die eine Mischung aus früheren Lösungen ist.

Sie können den Einsatz von Python Mechanik für private Mitglieder (Name Mangeln)

class A(ORMBaseClass): 
    __deleted = False 

    def delete(self): 
     self.__deleted = True 

    @property 
    def deleted(self): 
     return self.__deleted 

Ersten Mitteilung machen, wobei das Element zwei Strich wird mit der Variable privat zu machen. Die Verwendung von zwei Unterstrichen ist mehr als eine Konvention wie die vorgeschlagene Unterstreichung. Es wird dazu führen, dass Python den Namen des Attributs missbraucht. In diesem Fall ist der einzige Weg, um auf dieses Attribut zuzugreifen, obj._A__deleted Es ist immer noch beschreibbar, aber es ist viel besser als die Verwendung eines Unterstrichs. Jetzt haben Sie eine einfache Methode, die __deleted auf True und eine Eigenschaft setzt, die den Wert zurückgibt. Nichts kompliziert hier.

Warum Name Mangling ist wichtig?

Hier, wenn Sie, wo dies tun:

class B(A): 
    __deleted = True 

    @property 
    def deleted2(self): 
     return self.__deleted 

Ratet mal, was den Rückgabewert wäre:

obj = B() 
obj.deleted 

Wenn Sie False erraten, dann sind Sie richtig! Die Klasse B definiert ein Attribut mit dem Namen _B__deleted während der Klasse A _A__deleted.Wie Sie sehen können, verhindert die Namensänderung, dass die Unterklasse versehentlich auf Attribute der Oberklasse zugreifen kann. Und wenn Sie versuchen, auf __deleted von irgendwo außerhalb der Klassen zuzugreifen, wird das Attribut undefined sein ...

In der Theorie, wenn Sie wirklich privat haben wollten, könnten Sie eine Meta-Klasse verwenden, die so etwas mit zufälligen Namen jeder bauen wird Zeit eine Klasse aufgebaut ist.

Verwandte Themen