Wat is die maklikste, mees bondige manier om gekies eienskappe in 'n geval wees leesalleen?

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

  •  02-07-2019
  •  | 
  •  

Vra

In Python, ek wil gekies byvoorbeeld eienskappe van 'n klas leesalleen om kode buite die klas te maak. Ek wil daar wees geen manier buite-kode kan die kenmerk indirek verander, behalwe deur 'n beroep metodes op die instansie. Ek wil die sintaksis te bondig wees. Wat is die beste manier? (Ek gee my huidige beste onder antwoord ...)

Was dit nuttig?

Oplossing

Jy moet die @property versierder gebruik.

>>> 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

Ander wenke

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

Dit uitgange:

$ luislang ./p.py
c.fullaccess = 0
c.fullaccess = 1234
c.readonly = 22
Kan nie verander c.readonly
c.readonly = 22
c.readonly = 23

My vingers jeuk om te kan sê

    @readonly
    self.readonly = 22

d.w.z. Gebruik 'n versierder op 'n kenmerk. Dit sou so skoon wees ...

Hier is hoe:

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)

(met die aanvaarding foobar en blahblah is die eienskappe wat jy wil word slegs-lees.) Prepending twee beklemtoon om 'n kenmerk naam effektief verberg dit van buite die klas, sodat die interne weergawes sal nie toeganklik vanaf die buitekant. Dit net werk vir 'n nuwe styl klasse erfgename van voorwerp , aangesien dit hang af van property.

Aan die ander kant ... dit is 'n redelik dom ding om te doen. Hou veranderlikes private blyk 'n obsessie wat afkomstig is van C ++ en Java wees. Jou gebruikers moet die publiek koppelvlak gebruik om jou klas, want dit is goed ontwerpte, nie omdat jy hulle dwing om.

Edit: Lyk soos Kevin reeds 'n soortgelyke weergawe gepos

.

Daar is geen werklike manier om dit te doen. Daar is maniere om dit meer 'moeilike' maak, maar daar is geen begrip van heeltemal weggesteek, ontoeganklik klas skryf.

As die persoon met jou klas nie vertrou kan word om die API dokumente volg, dan is dit hul eie probleem. mense te doen dom dinge te beskerm beteken net dat hulle baie meer uitgebreide, ingewikkeld, en skadelike dom dinge sal doen om te probeer om te doen wat hulle moet nie gedoen het in die eerste plek.

Jy kan 'n metaclass dat motor-vou metodes (of klas eienskappe) wat 'n naamkonvensie in eienskappe (skaamteloos uit Verenigende Tipes en klasse 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))

Dit laat jou toe om te gebruik:

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

Ek is bewus daarvan dat William Keller is die skoonste oplossing by verre .. maar hier is iets wat ek het met ..

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)

En hier is die gebruik byvoorbeeld

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

Ongelukkig hierdie oplossing kan dit nie hanteer private veranderlikes (__ vernoem veranderlikes).

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top