Используя свойство () на classmethods

Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int:

int x;
x = 10;

В этом примере переменная x является int, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.

Но когда вы пытаетесь объявить ссылочный тип, произойдет что-то другое. Возьмите следующий код:

Integer num;
num = new Integer(10);

Первая строка объявляет переменную с именем num, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».

Во второй строке ключевое слово new используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования . (точка).

Exception, о котором вы просили, возникает, когда вы объявляете переменную, но не создавали объект. Если вы попытаетесь разыменовать num. Перед созданием объекта вы получите NullPointerException. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что «num не может быть инициализирован», но иногда вы пишете код, который непосредственно не создает объект.

Например, вы можете имеют следующий метод:

public void doSomething(SomeObject obj) {
   //do something to obj
}

В этом случае вы не создаете объект obj, скорее предполагая, что он был создан до вызова метода doSomething. К сожалению, этот метод можно вызвать следующим образом:

doSomething(null);

В этом случае obj имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.

Альтернативно, там могут быть случаи, когда цель метода заключается не только в том, чтобы работать с переданным в объекте, и поэтому нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething может быть записано как:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj != null) {
       //do something
    } else {
       //do something else
    }
}

Наконец, Как определить исключение & amp; причина использования Трассировки стека

151
задан Aaron Hall 10 April 2017 в 17:26
поделиться

8 ответов

Нет никакого разумного способа сделать эту "систему" свойства класса для работы в Python.

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

class ClassProperty(object):
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter
    def __get__(self, cls, owner):
        return getattr(cls, self.getter)()
    def __set__(self, cls, value):
        getattr(cls, self.setter)(value)

class MetaFoo(type):
    var = ClassProperty('getvar', 'setvar')

class Foo(object):
    __metaclass__ = MetaFoo
    _var = 5
    @classmethod
    def getvar(cls):
        print "Getting var =", cls._var
        return cls._var
    @classmethod
    def setvar(cls, value):
        print "Setting var =", value
        cls._var = value

x = Foo.var
print "Foo.var = ", x
Foo.var = 42
x = Foo.var
print "Foo.var = ", x

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

только когда-либо необходимо понимать этот вид вещей при реализации довольно усовершенствованной платформы. Как персистентность прозрачного объекта или система RPC или своего рода проблемно-ориентированный язык.

Однако в комментарии к предыдущему ответу, Вы говорите, что Вы

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

мне, кажется, что Вы действительно хотите, Наблюдатель шаблон разработки.

16
ответ дан ddaa 23 November 2019 в 22:16
поделиться

Половина решения, __ набор __ на классе не работает, все еще. Решением является пользовательский класс свойства, реализовывая и свойство и staticmethod

class ClassProperty(object):
    def __init__(self, fget, fset):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        return self.fget()

    def __set__(self, instance, value):
        self.fset(value)

class Foo(object):
    _bar = 1
    def get_bar():
        print 'getting'
        return Foo._bar

    def set_bar(value):
        print 'setting'
        Foo._bar = value

    bar = ClassProperty(get_bar, set_bar)

f = Foo()
#__get__ works
f.bar
Foo.bar

f.bar = 2
Foo.bar = 3 #__set__ does not
3
ответ дан Florian Bösch 23 November 2019 в 22:16
поделиться

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

у Вас есть доступ по крайней мере к одному экземпляру класса? Я могу думать о способе сделать это тогда:

class MyClass (object):
    __var = None

    def _set_var (self, value):
        type (self).__var = value

    def _get_var (self):
        return self.__var

    var = property (_get_var, _set_var)

a = MyClass ()
b = MyClass ()
a.var = "foo"
print b.var
3
ответ дан John Millikin 23 November 2019 в 22:16
поделиться

Дайте этому попытку, это обошлось без задания, имеющего необходимость измениться/добавить много существующего кода.

>>> class foo(object):
...     _var = 5
...     def getvar(cls):
...         return cls._var
...     getvar = classmethod(getvar)
...     def setvar(cls, value):
...         cls._var = value
...     setvar = classmethod(setvar)
...     var = property(lambda self: self.getvar(), lambda self, val: self.setvar(val))
...
>>> f = foo()
>>> f.var
5
>>> f.var = 3
>>> f.var
3

property для функции нужно два callable аргументы. дайте им обертки лямбды (который это передает экземпляр как свой первый аргумент), и все хорошо.

2
ответ дан Sufian 23 November 2019 в 22:16
поделиться

Вот мое предложение. Не используйте методы класса.

Серьезно.

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

<час>

, Если Вы просто хотите изменить значение, свойство не действительно очень полезно, он? Просто установите значение атрибута и будьте сделаны с ним.

свойство А должно только использоваться, если существует что-то для сокрытия - что-то, что могло бы измениться в будущем внедрении.

, Возможно, Вашим примером является путь, разделенный вниз, и существует некоторое адское вычисление, которое Вы бросили. Но не похоже, что свойство добавляет значительное значение.

влиявшие Java методы "конфиденциальности" (в Python, названия атрибута, которые начинаются _) не действительно очень полезны. Частный, от кого? Точка частных немного туманна, когда у Вас есть источник (как Вы делаете в Python.)

влиявшие Java методы get EJB-стиля и методы set (часто делавшийся как свойства в Python) там, чтобы упростить примитивный самоанализ Java, а также передать осмотр со статическим языковым компилятором. Все те методы get и методы set не так услужливы в Python.

-21
ответ дан S.Lott 23 November 2019 в 22:16
поделиться

Читая примечания к версии Python 2.2 , я обнаружил следующее:

Метод get [свойства] не будет вызываться, когда свойство доступно как класс атрибут (Cx) вместо атрибут экземпляра (C (). x). если ты хотите переопределить операцию __get__ для свойств при использовании в качестве класса атрибут, вы можете подклассифицировать свойство - это сам по себе тип нового стиля - чтобы расширить его метод __get__, или вы можете определить тип дескриптора с нуля путем создания класса нового стиля, который определяет __get__, __set__ и __delete__ методы.

ПРИМЕЧАНИЕ. Приведенный ниже метод на самом деле не работает для сеттеров, только для геттеров.

Поэтому я считаю, что предписанное решение - создать ClassProperty как подкласс свойства.

class ClassProperty(property):
    def __get__(self, cls, owner):
        return self.fget.__get__(None, owner)()

class foo(object):
    _var=5
    def getvar(cls):
        return cls._var
    getvar=classmethod(getvar)
    def setvar(cls,value):
        cls._var=value
    setvar=classmethod(setvar)
    var=ClassProperty(getvar,setvar)

assert foo.getvar() == 5
foo.setvar(4)
assert foo.getvar() == 4
assert foo.var == 4
foo.var = 3
assert foo.var == 3

Однако сеттеры на самом деле не работают:

foo.var = 4
assert foo.var == foo._var # raises AssertionError

foo._var не изменилось, вы просто заменили свойство новым значением.

Вы также можете использовать ClassProperty в качестве декоратора:

class foo(object):
    _var = 5

    @ClassProperty
    @classmethod
    def var(cls):
        return cls._var

    @var.setter
    @classmethod
    def var(cls, value):
        cls._var = value

assert foo.var == 5
70
ответ дан 23 November 2019 в 22:16
поделиться

Свойство создается в классе, но влияет на экземпляр. Так что, если вам нужно свойство classmethod, создайте свойство в метаклассе.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         pass
...     @classmethod
...     def getvar(cls):
...         return cls._var
...     @classmethod
...     def setvar(cls, value):
...         cls._var = value
...     
>>> foo.__metaclass__.var = property(foo.getvar.im_func, foo.setvar.im_func)
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

Но поскольку вы все равно используете метакласс, будет лучше, если вы просто переместите туда методы class.

>>> class foo(object):
...     _var = 5
...     class __metaclass__(type):  # Python 2 syntax for metaclasses
...         @property
...         def var(cls):
...             return cls._var
...         @var.setter
...         def var(cls, value):
...             cls._var = value
... 
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3

или, используя Python 3 метакласс = ... синтаксис и метакласс, определенный вне тела класса foo , и метакласс, отвечающий за установку начального значения _var :

>>> class foo_meta(type):
...     def __init__(cls, *args, **kwargs):
...         cls._var = 5
...     @property
...     def var(cls):
...         return cls._var
...     @var.setter
...     def var(cls, value):
...         cls._var = value
...
>>> class foo(metaclass=foo_meta):
...     pass
...
>>> foo.var
5
>>> foo.var = 3
>>> foo.var
3
76
ответ дан 23 November 2019 в 22:16
поделиться

Установка только для метакласса не поможет, если вы хотите чтобы получить доступ к свойству класса через созданный объект, в этом случае вам необходимо также установить обычное свойство для объекта (которое отправляется в свойство класса). Я думаю, что следующее немного более понятно:

#!/usr/bin/python

class classproperty(property):
    def __get__(self, obj, type_):
        return self.fget.__get__(None, type_)()

    def __set__(self, obj, value):
        cls = type(obj)
        return self.fset.__get__(None, cls)(value)

class A (object):

    _foo = 1

    @classproperty
    @classmethod
    def foo(cls):
        return cls._foo

    @foo.setter
    @classmethod
    def foo(cls, value):
        cls.foo = value

a = A()

print a.foo

b = A()

print b.foo

b.foo = 5

print a.foo

A.foo = 10

print b.foo

print A.foo
6
ответ дан 23 November 2019 в 22:16
поделиться
Другие вопросы по тегам:

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