Как понимание списков в python предотвращает побочные эффекты? [Дубликат]

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

Предположим, у вас есть веб-форма Contact.aspx, чей класс codebehind Свяжитесь с вами, и у вас есть имя объекта Contact.

Затем следующий код вызовет исключение NullReferenceException при вызове context.SaveChanges ()

Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line

Ради полноты класса DataContext

public class DataContext : DbContext 
{
    public DbSet Contacts {get; set;}
}

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

public partial class Contact 
{
    public string Name {get; set;}
}

Ошибка возникает, когда оба класса entity и codebehind находятся в одном и том же пространстве имен. Чтобы исправить это, переименуйте класс сущности или класс codebehind для Contact.aspx.

Причина. Я все еще не уверен в причине. Но всякий раз, когда какой-либо из классов сущностей расширяет System.Web.UI.Page, возникает эта ошибка.

Для обсуждения рассмотрим NullReferenceException в DbContext.saveChanges ()

99
задан Josh Lee 25 January 2011 в 22:04
поделиться

5 ответов

Учет списков утечки управляющей переменной цикла в Python 2, но не в Python 3. Вот Guido van Rossum (создатель Python) , объясняющий историю этого:

Мы также внесли еще одно изменение в Python 3, чтобы улучшить эквивалентность между пониманиями списков и выражений генератора. В Python 2, понимание списка «утечки» переменной управления циклом в окружающую область:

x = 'before'
a = [x for x in 1, 2, 3]
print x # this prints '3', not 'before'

Это был артефакт первоначальной реализации понимания списков; это был один из «грязных маленьких секретов» Питона в течение многих лет. Это началось как преднамеренный компромисс, чтобы сделать переписные слова ослепительно быстрыми, и, хотя это не было обычной ловушкой для начинающих, это определенно ужалило людей изредка. Для выражений генератора мы не могли этого сделать. Выражения генератора реализуются с использованием генераторов, выполнение которых требует отдельного кадра выполнения. Таким образом, выражения генератора (особенно, если они повторяются по короткой последовательности) были менее эффективны, чем понимание списков.

Однако в Python 3 мы решили исправить «грязный маленький секрет» из понятий списка, используя та же стратегия реализации, что и для выражений генератора. Таким образом, в Python 3 приведенный выше пример (после модификации использования print (x) :-) будет печатать «before», доказывая, что «x» в понимании списка временно затеняет, но не переопределяет «x» в окружающем область.

140
ответ дан Steven Rumbalski 1 September 2018 в 07:55
поделиться

Да, перечислите «утечку» их переменных в Python 2.x, как и для циклов.

В ретроспективе это было признано ошибкой, и ее избегали с помощью выражений генератора. EDIT: как Мэтт Б. отмечает , его также избегали, когда синтаксисы синтаксиса и синтаксиса слова были переданы из Python 3.

Поведение списков List должно было быть оставлено, как и в Python 2, но он полностью исправлен в Python 3.

Это означает, что во всех:

list(x for x in a if x>32)
set(x//4 for x in a if x>32)         # just another generator exp.
dict((x, x//16) for x in a if x>32)  # yet another generator exp.
{x//4 for x in a if x>32}            # 2.7+ syntax
{x: x//16 for x in a if x>32}        # 2.7+ syntax

x всегда является локальным для выражения, а они:

[x for x in a if x>32]
set([x//4 for x in a if x>32])         # just another list comp.
dict([(x, x//16) for x in a if x>32])  # yet another list comp.

в Python 2.x все протекают переменную x в окружающую область.


UPDATE для Python 3.8 (?): PEP 572 ] представит оператор присваивания :=, который намеренно просачивается из понятий и выражений генератора! Это мотивировано, по существу, двумя вариантами использования: захват «свидетеля» из функций раннего завершения, таких как any() и all():

if any((comment := line).startswith('#') for line in lines):
    print("First comment:", comment)
else:
    print("There are no comments")

и обновление изменчивого состояния:

total = 0
partial_sums = [total := total + v for v in values]

Для точного определения области обзора см. Приложение B . Переменная назначается в ближайшем окружении def или lambda, если только эта функция не объявит ее nonlocal или global.

47
ответ дан Beni Cherniavsky-Paskin 1 September 2018 в 07:55
поделиться

Интересно, что это не влияет на словарь или задание понятий.

>>> [x for x in range(1, 10)]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> x
9
>>> {x for x in range(1, 5)}
set([1, 2, 3, 4])
>>> x
9
>>> {x:x for x in range(1, 100)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19, 20: 20, 21: 21, 22: 22, 23: 23, 24: 24, 25: 25, 26: 26, 27: 27, 28: 28, 29: 29, 30: 30, 31: 31, 32: 32, 33: 33, 34: 34, 35: 35, 36: 36, 37: 37, 38: 38, 39: 39, 40: 40, 41: 41, 42: 42, 43: 43, 44: 44, 45: 45, 46: 46, 47: 47, 48: 48, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57, 58: 58, 59: 59, 60: 60, 61: 61, 62: 62, 63: 63, 64: 64, 65: 65, 66: 66, 67: 67, 68: 68, 69: 69, 70: 70, 71: 71, 72: 72, 73: 73, 74: 74, 75: 75, 76: 76, 77: 77, 78: 78, 79: 79, 80: 80, 81: 81, 82: 82, 83: 83, 84: 84, 85: 85, 86: 86, 87: 87, 88: 88, 89: 89, 90: 90, 91: 91, 92: 92, 93: 93, 94: 94, 95: 95, 96: 96, 97: 97, 98: 98, 99: 99}
>>> x
9

Однако он был исправлен в 3, как указано выше.

2
ответ дан Chris Travers 1 September 2018 в 07:55
поделиться

Да, там происходит присваивание, как и в цикле for. Никакая новая область не создается.

Это определенно ожидаемое поведение: в каждом цикле значение привязано к указанному вами имени. Например,

>>> x=0
>>> a=[1,54,4,2,32,234,5234,]
>>> [x for x in a if x>32]
[54, 234, 5234]
>>> x
5234

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

7
ответ дан JAL 1 September 2018 в 07:55
поделиться

некоторое обходное решение для python 2.6, когда это поведение нежелательно

# python
Python 2.6.6 (r266:84292, Aug  9 2016, 06:11:56)
Type "help", "copyright", "credits" or "license" for more information.
>>> x=0
>>> a=list(x for x in xrange(9))
>>> x
0
>>> a=[x for x in xrange(9)]
>>> x
8
0
ответ дан Marek Slebodnik 1 September 2018 в 07:55
поделиться
Другие вопросы по тегам:

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