Каков самый легкий, самый краткий способ заставить выбранные атрибуты в экземпляре быть только для чтения?

Вы можете использовать lookaround.

/^abc(?!.*abc).*123.*(?<!xyz.*)xyz$/g

(я его не тестировал.)

8
задан William Keller 24 September 2008 в 02:40
поделиться

6 ответов

Необходимо использовать @property декоратор.

>>> 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
7
ответ дан 5 December 2019 в 14:07
поделиться
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

Это производит:

Python $./p.py
c.fullaccess = 0
c.fullaccess = 1234
c.readonly = 22
Не может изменить c.readonly
c.readonly = 22
c.readonly = 23

Мои пальцы жаждут смочь сказать

    @readonly
    self.readonly = 22

т.е. используйте декоратора на атрибуте. Это было бы настолько чисто...

2
ответ дан 5 December 2019 в 14:07
поделиться

Вы могли использовать метакласс, который автопереносит методы (или атрибуты класса), которые следуют соглашению о присвоении имен в свойства (бесстыдно взятый от Объединения Типов и Классов в 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))

Это позволяет Вам использовать:

class A:
    __metaclass__ = autosuprop
    def _readonly(self):
        return __x
0
ответ дан 5 December 2019 в 14:07
поделиться

Нет никакого реального способа сделать это. Существуют способы сделать это более 'трудным', но нет никакого понятия абсолютно скрытых, недоступных атрибутов класса.

Если человеку, использующему Ваш класс, нельзя доверять для следования документам API, то это - их собственная проблема. Защита людей от выполнения глупого материала просто означает, что они сделают намного более тщательно продуманный, сложный, и повреждение глупого материала, чтобы попытаться сделать независимо от того, что они не должны были делать во-первых.

1
ответ дан 5 December 2019 в 14:07
поделиться

Вот то, как:

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)

(Принятие foobar и blahblah атрибуты, Вы хотите быть только для чтения.) Предварительное ожидание двух символов нижнего подчеркивания к названию атрибута эффективно скрывает его снаружи класса, таким образом, внутренние версии не будут доступны с внешней стороны. Это только работает на модернизированные классы, наследовавшиеся объекту, так как он зависит от property.

С другой стороны... это - довольно глупая вещь сделать. Хранение частных переменных, кажется, навязчивая идея, которая прибывает из C++ и Java. Ваши пользователи должны использовать открытый интерфейс для Вашего класса, потому что он хорошо разработан, не потому что Вы вынуждаете их к.

Править: Похож на Kevin, уже отправил аналогичную версию.

2
ответ дан 5 December 2019 в 14:07
поделиться

Я знаю, что Уильям Келлер - безусловно самое чистое решение .. но вот кое-что, что я придумал ..

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)

А вот пример использования

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

К сожалению, это решение не может обрабатывать частные переменные (__ именованные переменные).

0
ответ дан 5 December 2019 в 14:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: