python: неизменные закрытые переменные класса? - PullRequest
10 голосов
/ 13 сентября 2011

Есть ли способ перевести этот Java-код в Python?

class Foo
{
    final static private List<Thingy> thingies = 
       ImmutableList.of(thing1, thing2, thing3);
}

например, thingies - это неизменный закрытый список Thingy объектов, принадлежащих классу Foo, а не его экземпляру.

Я знаю, как определить статические переменные класса из этого вопроса Статические переменные класса в Python , но я не знаю, как сделать их неизменными и приватными.

Ответы [ 4 ]

18 голосов
/ 13 сентября 2011

В Python принято использовать префикс _ в именах атрибутов для обозначения protected и префикс __ для обозначения private. Это не обеспечивается языком; от программистов ожидается, что они не будут писать код, основанный на общедоступных данных.

Если вы действительно хотите применить неизменность, вы можете использовать метакласс [ docs ] (класс класса). Просто измените __setattr__ и __delattr__, чтобы вызвать исключения, когда кто-то пытается изменить его, и сделайте его tuple (неизменный список) [ docs ] .

class FooMeta(type):
    """A type whose .thingies attribute can't be modified."""

    def __setattr__(cls, name, value):
        if name == "thingies":
            raise AttributeError("Cannot modify .thingies")
        else:
            return type.__setattr__(cls, name, value)

    def __delattr__(cls, name):
        if name == "thingies":
            raise AttributeError("Cannot delete .thingies")
        else:
            return type.__delattr__(cls, name)

thing1, thing2, thing3 = range(3)

class Foo(object):
    __metaclass__ = FooMeta
    thingies = (thing1, thing2, thing3)
    other = [1, 2, 3]

Примеры

print Foo.thingies # prints "(0, 1, 2)"
Foo.thingies = (1, 2) # raises an AttributeError
del Foo.thingies # raise an AttributeError
Foo.other = Foo.other + [4] # no exception
print Foo.other # prints "[1, 2, 3, 4]"

Технически все еще возможно изменить их, пройдя внутренние .__dict__ атрибуты класса, но этого должно быть достаточно для сдерживания большинства пользователей, очень трудно полностью защитить объекты Python.

13 голосов
/ 13 сентября 2011

Вы не можете делать ни одну из этих вещей в Python, во всяком случае, в том смысле, в котором вы делаете это в Java.

По соглашению, имена с префиксом подчеркивания считаются закрытыми и не должны быть доступны извнереализация, но ничто в Python не обеспечивает соблюдения этого соглашения.Это скорее предупреждение о том, что вы ошибаетесь с деталями реализации, которые могут измениться без предупреждения в будущей версии кода.

6 голосов
/ 13 сентября 2011

Вы можете сделать его недоступным для записи (немного отличным от неизменяемого), используя свойства, но нет возможности сделать его закрытым - это противоречит философии Python.

class Foo(object):    # don't need 'object' in Python 3
    @property
    def thingies(self):
        return 'thing1', 'thing2', 'thing3'

f = Foo()
print f.thingies
#('thing1', 'thing2', 'thing3')
f.thingies = 9
#Traceback (most recent call last):
#  File "test.py", line 8, in <module>
#    f.thingies = 9
#AttributeError: can't set attribute

Независимо от того, является ли оно неизменным илине зависит от того, что вы возвращаете;если вы возвращаете изменяемый объект, вы можете изменить его, чтобы в и эти изменения отображались в экземпляре / классе.

class FooMutable(object):
    _thingies = [1, 2, 3]
    @property
    def thingies(self):
        return self._thingies

foo = FooMutable()
foo.thingies.append(4)
print foo.thingies
# [1, 2, 3, 4]

Это позволит вам изменить thingies, ипоскольку возвращаемый объект является тем же объектом, который хранится в экземпляре / классе, изменения будут отражены при последующем доступе.

Сравните это с:

class FooMutable(object):
    @property
    def thingies(self):
        return [1, 2, 3]

foo = FooMutable()
foo.thingies.append(4)
print foo.thingies
# [1, 2, 3]

Поскольку каждый раз возвращается новый списоквремя, изменения к нему не отражаются в последующих доступах.

1 голос
/ 13 сентября 2011

Вы хотите посмотреть на функцию property().Это позволяет вам определять свои собственные Getter и Setter для атрибута члена класса.Это может выглядеть примерно так:

class myClass(object):
  _x = "Hard Coded Value"

  def set_x(self, val): return

  def get_x(self): return self._x

  def del_x(self): return

  x = property(get_x, set_x, del_x, "I'm an immutable property named 'x'")

Я недостаточно использовал это, чтобы быть уверенным, можно ли его использовать для создания чего-то «частного», поэтому вам придется вникать в это самостоятельно, но isinstance может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...