Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа 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; причина использования Трассировки стека
Нет никакого разумного способа сделать эту "систему" свойства класса для работы в 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 или своего рода проблемно-ориентированный язык.
Однако в комментарии к предыдущему ответу, Вы говорите, что Вы
потребность изменить атрибут, который таким способом, который замечен всеми экземплярами класса, и в объеме, от которого называют эти методы класса, не имеет ссылок на все экземпляры класса.
мне, кажется, что Вы действительно хотите, Наблюдатель шаблон разработки.
Половина решения, __ набор __ на классе не работает, все еще. Решением является пользовательский класс свойства, реализовывая и свойство и 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
, поскольку я должен изменить атрибут, который таким способом, который замечен всеми экземплярами класса, и в объеме, от которого называют эти методы класса, не имеет ссылок на все экземпляры класса.
у Вас есть доступ по крайней мере к одному экземпляру класса? Я могу думать о способе сделать это тогда:
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
Дайте этому попытку, это обошлось без задания, имеющего необходимость измениться/добавить много существующего кода.
>>> 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
аргументы. дайте им обертки лямбды (который это передает экземпляр как свой первый аргумент), и все хорошо.
Вот мое предложение. Не используйте методы класса.
Серьезно.
, Какова причина использования методов класса в этом случае? Почему бы не обычный объект обычного класса?
<час>, Если Вы просто хотите изменить значение, свойство не действительно очень полезно, он? Просто установите значение атрибута и будьте сделаны с ним.
свойство А должно только использоваться, если существует что-то для сокрытия - что-то, что могло бы измениться в будущем внедрении.
, Возможно, Вашим примером является путь, разделенный вниз, и существует некоторое адское вычисление, которое Вы бросили. Но не похоже, что свойство добавляет значительное значение.
влиявшие Java методы "конфиденциальности" (в Python, названия атрибута, которые начинаются _) не действительно очень полезны. Частный, от кого? Точка частных немного туманна, когда у Вас есть источник (как Вы делаете в Python.)
влиявшие Java методы get EJB-стиля и методы set (часто делавшийся как свойства в Python) там, чтобы упростить примитивный самоанализ Java, а также передать осмотр со статическим языковым компилятором. Все те методы get и методы set не так услужливы в Python.
Читая примечания к версии 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
Свойство создается в классе, но влияет на экземпляр. Так что, если вам нужно свойство 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
Установка только для метакласса не поможет, если вы хотите чтобы получить доступ к свойству класса через созданный объект, в этом случае вам необходимо также установить обычное свойство для объекта (которое отправляется в свойство класса). Я думаю, что следующее немного более понятно:
#!/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