NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Если вы хотите избежать дублирования кода и используете версию Python до 3.3 (где contextlib.ExitStack
недоступен), вы можете сделать что-то вроде:
class dummy_context_mgr():
def __enter__(self):
return None
def __exit__(self, exc_type, exc_value, traceback):
return False
или:
import contextlib
@contextlib.contextmanager
def dummy_context_mgr():
yield None
, а затем использовать его как:
with get_stuff() if needs_with() else dummy_context_mgr() as gs:
# do stuff involving gs or not
Вы также можете заставить get_stuff()
возвращать разные вещи на основе needs_with()
.
Сторонний вариант для достижения именно этого: https://pypi.python.org/pypi/conditional
from conditional import conditional
with conditional(needs_with(), get_stuff()):
# do stuff
as ...
в конце инструкции with
?
– Craig McQueen
9 December 2016 в 01:40
with conditional(needs_with(), get_stuff()) as stuff:
даст вам ссылку на менеджер контекста get_stuff()
(если и только если условие выполнено, в противном случае вы получите None
)
– Anentropic
9 December 2016 в 12:27
Python 3.3 представил contextlib.ExitStack
только для такой ситуации. Он дает вам «стек», к которому вы добавляете менеджеров контекста по мере необходимости. В вашем случае вы сделаете следующее:
from contextlib import ExitStack
with ExitStack() as stack:
if needs_with():
gs = stack.enter_context(get_stuff())
# do nearly the same large block of stuff,
# involving gs or not, depending on needs_with()
Все, что введено в stack
, автоматически exit
ed в конце инструкции with
, как обычно. (Если ничего не введено, это не проблема.) В этом примере все, что было возвращено get_stuff()
, автоматически exit
.
Если вам нужно использовать более раннюю версию python, вы можете иметь возможность использовать модуль contextlib2
, хотя это не является стандартным. Он поддерживает эту и другие функции в более ранних версиях python. Вы можете даже сделать условный импорт, если вам нравится этот подход.
with get_stuff() if needs_with() else ExitStack() as gs
.
– farsil
20 February 2017 в 15:14
Вы можете использовать contextlib.nested
, чтобы поставить 0 или более менеджеров контекста в один оператор with
.
>>> import contextlib
>>> managers = []
>>> test_me = True
>>> if test_me:
... managers.append(open('x.txt','w'))
...
>>> with contextlib.nested(*managers):
... pass
...
>>> # see if it closed
... managers[0].write('hello')
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ValueError: I/O operation on closed file
Это решение имеет свои причуды, и я просто заметил, что с 2,7 его устарело , Я написал свой собственный менеджер контекстов для управления несколькими контекстными менеджерами. До сих пор это работало на меня, но я не рассматривал крайние условия
class ContextGroup(object):
"""A group of context managers that all exit when the group exits."""
def __init__(self):
"""Create a context group"""
self._exits = []
def add(self, ctx_obj, name=None):
"""Open a context manager on ctx_obj and add to this group. If
name, the context manager will be available as self.name. name
will still reference the context object after this context
closes.
"""
if name and hasattr(self, name):
raise AttributeError("ContextGroup already has context %s" % name)
self._exits.append(ctx_obj.__exit__)
var = ctx_obj.__enter__()
if name:
self.__dict__[name] = var
def exit_early(self, name):
"""Call __exit__ on named context manager and remove from group"""
ctx_obj = getattr(self, name)
delattr(self, name)
del self._exits[self._exits.index(ctx_obj)]
ctx_obj.__exit__(None, None, None)
def __enter__(self):
return self
def __exit__(self, _type, value, tb):
inner_exeptions = []
for _exit in self._exits:
try:
_exit(_type, value, tb )
except Exception, e:
inner_exceptions.append(e)
if inner_exceptions:
r = RuntimeError("Errors while exiting context: %s"
% (','.join(str(e)) for e in inner_exceptions))
def __setattr__(self, name, val):
if hasattr(val, '__exit__'):
self.add(val, name)
else:
self.__dict__[name] = val
contextlib.ExitStack
, что, похоже, очень сильно влияет на ваш ContextGroup
. Я скажу, что я немного удивлен, что он не был обращен, но если вы захотите потребовать python & gt; = 3.3, это может быть хорошей надежной альтернативой для вас.
– Mike
14 January 2016 в 21:02
contextlib2
представляет собой пакет pypi, который передал ExitStack
в python 2
– Anthony Sottile
3 July 2017 в 16:27
with get_stuff() if should_get_stuff() else dont() as gs:
? – Riaz Rizvi 25 March 2016 в 16:12