Я могу создать “представление” о списке Python?

Элемент, который вы пытались найти, не был в DOM , когда ваш скрипт работал.

Позиция вашего DOM-зависимого скрипта может оказать глубокое влияние на его поведение. Браузеры анализируют HTML-документы сверху донизу. Элементы добавляются в DOM, и сценарии выполняются (как правило), когда они встречаются. Это означает, что порядок имеет значение. Как правило, скрипты не могут найти элементы, которые появляются позже в разметке, потому что эти элементы еще не добавлены в DOM.

Рассмотрим следующую разметку; сценарий # 1 не находит

, а сценарий # 2 преуспевает:


test div

Итак, что вы должны делать? У вас есть несколько вариантов:


Вариант 1: Переместите свой скрипт

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


  
  

Примечание: размещение скриптов внизу как правило, считается лучшей практикой .


Вариант 2: jQuery's ready()

Отмените свой сценарий до тех пор, пока DOM не будет полностью проанализирован, используя ready() :



Примечание. Вы можете просто привязать к DOMContentLoaded или window.onload, но у каждого есть свои оговорки. jQuery ready() предоставляет гибридное решение.


Вариант 3: Делегирование событий

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

blockquote>

Когда элемент вызывает событие (при условии, что это bubbling g6], и ничто не останавливает его распространение), каждый родитель в родословной этого элемента также получает событие. Это позволяет нам привязать обработчик к существующему элементу и примерным событиям, когда они пузырятся от его потомков ... даже те, которые добавлены после присоединения обработчика. Все, что нам нужно сделать, это проверить событие, чтобы узнать, был ли он поднят нужным элементом и, если да, запустите наш код.

jQuery on() выполняет эту логику для нас. Мы просто предоставляем имя события, селектор для желаемого потомка и обработчик событий:



Примечание: Обычно этот шаблон зарезервированы для элементов, которые не существовали во время загрузки или , чтобы избежать прикрепления большого количества обработчиков. Также стоит отметить, что, пока я прикреплял обработчик к document (для демонстрационных целей), вы должны выбрать ближайшего надежного предка.


Вариант 4: Атрибут defer

Используйте атрибут defer в

Для справки, вот код из этого внешнего скрипта :

document.getElementById("test").addEventListener("click", function(e){
   console.log("clicked: %o", this); 
});

Примечание: атрибут defer, безусловно, кажется , как волшебная пуля , но важно знать об оговорках ... 1. defer может использоваться только для внешних скриптов, т. е. для тех, у кого есть атрибут src. 2. знать о поддержке браузера , то есть: ошибка реализации в IE & lt; 10

41
задан Wai Yip Tung 14 August 2010 в 23:05
поделиться

6 ответов

В стандартной библиотеке Python нет класса «фрагмент списка» (и нет ни одного встроенного). Итак, вам действительно нужен класс, хотя он не обязательно должен быть большим, особенно если вас устраивает «только для чтения» и «компактный» фрагмент. Например: [

import collections

class ROListSlice(collections.Sequence):

    def __init__(self, alist, start, alen):
        self.alist = alist
        self.start = start
        self.alen = alen

    def __len__(self):
        return self.alen

    def adj(self, i):
        if i<0: i += self.alen
        return i + self.start

    def __getitem__(self, i):
        return self.alist[self.adj(i)]

] Это имеет некоторые ограничения (не поддерживает «нарезку среза»), но для большинства целей может подойти.

Чтобы сделать эту последовательность r / w, вам нужно добавить __ setitem __ , __ delitem __ и insert :

class ListSlice(ROListSlice):

    def __setitem__(self, i, v):
        self.alist[self.adj(i)] = v

    def __delitem__(self, i, v):
        del self.alist[self.adj(i)]
        self.alen -= 1

    def insert(self, i, v):
        self.alist.insert(self.adj(i), v)
        self.alen += 1
32
ответ дан 27 November 2019 в 00:39
поделиться

На самом деле не слишком трудно реализовать это самостоятельно использование range.*, можно нарезать диапазон, и это делает всю сложную арифметику для Вас:

>>> range(20)[10:]
range(10, 20)
>>> range(10, 20)[::2]
range(10, 20, 2)
>>> range(10, 20, 2)[::-3]
range(18, 8, -6)

, Таким образом, Вам просто нужен класс объекта, который содержит ссылку на исходную последовательность и диапазон. Вот код для такого класса (не слишком большой, я надеюсь):

class SequenceView:

    def __init__(self, sequence, range_object=None):
        if range_object is None:
            range_object = range(len(sequence))
        self.range    = range_object
        self.sequence = sequence

    def __getitem__(self, key):
        if type(key) == slice:
            return SequenceView(self.sequence, self.range[key])
        else:
            return self.sequence[self.range[key]]

    def __setitem__(self, key, value):
        self.sequence[self.range[key]] = value

    def __len__(self):
        return len(self.range)

    def __iter__(self):
        for i in self.range:
            yield self.sequence[i]

    def __repr__(self):
        return f"SequenceView({self.sequence!r}, {self.range!r})"

    def __str__(self):
        if type(self.sequence) == str:
            return ''.join(self)
        elif type(self.sequence) in (list, tuple):
            return str(type(self.sequence)(self))
        else:
            return repr(self)

(Это было bodged вместе приблизительно за 5 минут, поэтому удостоверьтесь, что Вы тестируете его полностью перед использованием его где угодно важный.)

Использование:

>>> p = list(range(10))
>>> q = SequenceView(p)[3:6]
>>> print(q)
[3, 4, 5]
>>> q[1] = -1
>>> print(q)
[3, -1, 5]
>>> print(p)
[0, 1, 2, 3, -1, 5, 6, 7, 8, 9]

* в Python 3

0
ответ дан 27 November 2019 в 00:39
поделиться

Вы можете отредактировать: not сделать что-то вроде

shiftedlist = type('ShiftedList',
                   (list,),
                   {"__getitem__": lambda self, i: list.__getitem__(self, i + 3)}
                  )([1, 2, 3, 4, 5, 6])

По сути, это однострочный, это не очень Pythonic, но это основная суть.

edit: Я с опозданием понял, что это не работает, потому что list () , по сути, сделает мелкую копию переданного списка. Таким образом, это будет более или менее похоже на разрезание списка. Фактически меньше из-за отсутствия переопределения __ len __ . Вам нужно будет использовать прокси-класс; см. Mr. Ответ Мартелли для подробностей.

0
ответ дан 27 November 2019 в 00:39
поделиться

Изменить: Аргумент объекта должен быть объектом, который поддерживает интерфейс вызова буфера (например, строки, массивы и буферы). - так что нет, к сожалению.

Думаю, тип буфера - это то, что вы ищете.

Пример вставки со связанной страницы:

>>> s = bytearray(1000000)   # a million zeroed bytes
>>> t = buffer(s, 1)         # slice cuts off the first byte
>>> s[1] = 5                 # set the second element in s
>>> t[0]                     # which is now also the first element in t!
'\x05' 
1
ответ дан 27 November 2019 в 00:39
поделиться

Возможно, просто используйте массив numpy:

In [19]: import numpy as np

In [20]: l=np.arange(10)

Базовое нарезание массивов numpy возвращает представление , а не копию:

In [21]: lv=l[3:6]

In [22]: lv
Out[22]: array([3, 4, 5])

Изменение l влияет на lv :

In [23]: l[4]=-1

In [24]: lv
Out[24]: array([ 3, -1,  5])

И изменение lv влияет на l :

In [25]: lv[1]=4

In [26]: l
Out[26]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
29
ответ дан 27 November 2019 в 00:39
поделиться

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

l = [1,2,3,4,5]
lv = (l[i] for i in range(1,4))

lv.next()   # 2
l[2]=-1
lv.next()   # -1
lv.next()   # 4

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

5
ответ дан 27 November 2019 в 00:39
поделиться
Другие вопросы по тегам:

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