Was ist die einfachste, prägnante Art und Weise ausgewählte Attribute nur lesbar in einer Instanz zu machen sein?

StackOverflow https://stackoverflow.com/questions/125034

  •  02-07-2019
  •  | 
  •  

Frage

In Python, möchte ich machen ausgewählt Instanzattribute einer Klasse nur lesbar außerhalb der Klasse Code werden. Ich möchte es keine Möglichkeit, außerhalb Code sein kann das Attribut ändern, außer indirekt durch Methoden auf der Instanz aufgerufen wird. Ich möchte die Syntax prägnant sein. Was ist der beste Weg? (Ich gebe meine aktuelle beste Antwort unten ...)

War es hilfreich?

Lösung

Sie sollten den @property Dekorateur verwenden.

>>> class a(object):
...     def __init__(self, x):
...             self.x = x
...     @property
...     def xval(self):
...             return self.x
... 
>>> b = a(5)
>>> b.xval
5
>>> b.xval = 6
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Andere Tipps

class C(object):

    def __init__(self):

        self.fullaccess = 0
        self.__readonly = 22 # almost invisible to outside code...

    # define a publicly visible, read-only version of '__readonly':
    readonly = property(lambda self: self.__readonly)

    def inc_readonly( self ):
        self.__readonly += 1

c=C()

# prove regular attribute is RW...
print "c.fullaccess = %s" % c.fullaccess
c.fullaccess = 1234
print "c.fullaccess = %s" % c.fullaccess

# prove 'readonly' is a read-only attribute
print "c.readonly = %s" % c.readonly
try:
    c.readonly = 3
except AttributeError:
    print "Can't change c.readonly"
print "c.readonly = %s" % c.readonly

# change 'readonly' indirectly...
c.inc_readonly()
print "c.readonly = %s" % c.readonly

Diese Ausgänge:

$ python ./p.py
c.fullaccess = 0
c.fullaccess = 1234
c.readonly = 22
Kann nicht ändern c.readonly
c.readonly = 22
c.readonly = 23

Meine Finger jucken sagen zu können,

    @readonly
    self.readonly = 22

d., Einen Dekorateur auf einem Attribute verwenden. Es wäre so sauber ...

Hier ist, wie:

class whatever(object):
  def __init__(self, a, b, c, ...):
    self.__foobar = 1
    self.__blahblah = 2

  foobar = property(lambda self: self.__foobar)
  blahblah = property(lambda self: self.__blahblah)

(Unter der Annahme, foobar und blahblah sind die Attribute, die Sie wollen schreibgeschützt werden.) Voranstellen zwei unterstreicht, um einen Attributnamen es effektiv versteckt von außerhalb der Klasse, so dass die internen Versionen werden nicht von außen zugänglich. Dieses funktioniert nur für neuen Stil Klassen von Objekt vererben , da es auf property abhängig ist.

Auf der anderen Seite ... das ist eine ziemlich dumme Sache zu tun. Keeping scheint Variablen privat eine Obsession zu sein, die von C ++ und Java kommt. Ihre Benutzer die öffentliche Schnittstelle zu Ihrer Klasse verwenden sollten, weil es gut gestaltete, nicht weil man sie erzwingen.

Edit: Sieht aus wie Kevin bereits eine ähnliche Version geschrieben

.

Es gibt keinen wirklichen Weg, dies zu tun. Es Möglichkeiten es ‚schwierig‘ zu machen, aber es gibt kein Konzept völlig verborgen, unzugänglich Klassenattribute.

Wenn die Person Ihrer Klasse mit nicht vertraut werden kann, um die API-Dokumentation zu folgen, dann ist das ihr eigenes Problem. Leute tun dumme Sachen zu schützen bedeutet nur, dass sie weit aufwändigere, kompliziert und schädlich dummes Zeug, um zu versuchen zu tun, was sie nicht sind in erster Linie zu tun.

tun

Sie könnten eine Metaklasse verwenden, die Auto-Wraps Methoden (oder Klassenattribut), die eine Namenskonvention in dem Eigentum folgt (schamlos genommen von Unifying-Typen und Klassen in Python 2.2 :

class autoprop(type):
    def __init__(cls, name, bases, dict):
        super(autoprop, cls).__init__(name, bases, dict)
        props = {}
        for name in dict.keys():
            if name.startswith("_get_") or name.startswith("_set_"):
                props[name[5:]] = 1
        for name in props.keys():
            fget = getattr(cls, "_get_%s" % name, None)
            fset = getattr(cls, "_set_%s" % name, None)
            setattr(cls, name, property(fget, fset))

Auf diese Weise können Sie verwenden:

class A:
    __metaclass__ = autosuprop
    def _readonly(self):
        return __x

Ich bin mir bewusst, dass William Keller die sauberste Lösung ist bei weitem .. aber hier ist etwas, das ich mit .. kam

class readonly(object):
    def __init__(self, attribute_name):
        self.attribute_name = attribute_name

    def __get__(self, instance, instance_type):
        if instance != None:
            return getattr(instance, self.attribute_name)
        else:
            raise AttributeError("class %s has no attribute %s" % 
                                 (instance_type.__name__, self.attribute_name))

    def __set__(self, instance, value):
        raise AttributeError("attribute %s is readonly" % 
                              self.attribute_name)

Und hier ist das Verwendungsbeispiel

class a(object):
    def __init__(self, x):
        self.x = x
    xval = readonly("x")

Leider kann diese Lösung nicht umgehen private Variablen (__ benannten Variablen).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top