Поиск по блогу

вторник, 25 ноября 2014 г.

О конструировании списков в Python и хорошем стиле программирования

Здесь я "открыл", что конструктор item['new']=["" for j in range(len(iu))] выдает список, который ничуть не короче, чем item['new']=["WoW" for j in range(len(iu))] И весь этот пост наполнен упражнениями, ...рассуждениями пытливого туповатого самоучки, который завидует тем, кому преподы все подают на блюдечке...

Начнем со стиля. Если бы у меня были бы практические занятия в ВУЗе, то хорошие преподаватели в многочисленных примерах просто бы использовали этот конструктор... и при этом говорили бы , что это "хороший стиль программирования"... Я бы запомнил все "между делом". И мне бы не пришлось тратить полтора часа на все нижеприведенные изыскания... Хорошая академическая школа - это преподы, которые передают тебе свои "открытия"... Много хороших преподов - огромная экономия времени... и никакого когнитивного диссонанса...

Вот очевидный, вроде бы, вариант

Когда для заполнения списка используется метод .append(), то к списку последовательно добавляются новые члены.
Очевидно, что эта процедура и уопрядочивает список. Если у нас словарь, состоящий из списков, то можно перебрать один образцовый список ('url'), и для каждого элемента этого списка получить индекс (j - порядковый номер). Затем можно последовательно присоединить к новому пустому списку новые элементы .append()

In [1]:
item={'url':['url1','url2','url3','url4','url5',], 
      'oth':['oth1','oth2','oth3','oth4','oth5',]}
In [2]:
item['new']=[]
In [7]:
iurl=item['url']     #the list of url
for surl in iurl:       # iterate 'url'
    j=iurl.index(surl)   # take index of eash surl
    item['new'].append(j)
In [8]:
item
Out[8]:
{'new': [0, 1, 2, 3, 4],
 'oth': ['oth1', 'oth2', 'oth3', 'oth4', 'oth5'],
 'url': ['url1', 'url2', 'url3', 'url4', 'url5']}

Так, да не так - лучше бы сразу задать список определенной длины

Однако, где гарантия, что процессор переберет "образцовый" список в правильной последовательности? Оказывается в Python возможны такие варианты, в часности, когда мы используем асинхронный поток... например, библиотеку Twisted... У меня даже есть конкретный пример.

При повторении вот этого примеера Скачал Python-Web-Crawler и сразу же запустил

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

Потому решил "дунуть на воду" при конструировании pipelines в Scrapy. Поскольку мне лень разбираться в тонкостях работы def process_item(self, item, spider), а самое главное, используются итераторы, который перебирает НЕупорядоченную (по определению) последовательность, и таких итераторов много, то надженее другой подход.

  1. Выбираем "образцовый" список и вычисляем его длину.
  2. Создаем новый список такой же длинны с элементами Null
  3. Все, списки синхронизированы, теперь можно вырезать из элементов "образцового" любые фрагменты и вставлять их в новый.

Upgrade: Вот здесь я только-что изобрел детский трехколесный велосипед. Обидно конечно. Но надеюсь использовать этот пост, как пример для анализа особенностей человеческого мышления

In [9]:
iu=item['url']
In [18]:
iu[-1], iu.index(iu[-1]) #Вспоминаем про последний элемент списка
Out[18]:
('url5', 4)
In [19]:
len(iu) # Вспоминаем про встроенную функцию
Out[19]:
5
In [22]:
item['new']=[]
for i in range(len(iu)):
    item['new'].append(i)
In [23]:
item['new']
Out[23]:
[0, 1, 2, 3, 4]
In []:
Пример автозаполнителя листа из документации

A compact way to process all or part of the elements in a sequence and return a list with the results.

In [24]:
result = ["0x%02x" % x for x in range(6) if x % 2 == 0]

... generates a list of strings containing even hex numbers (0x..) in the range from 0 to 255. The if clause is optional. If omitted, all elements in range(256) are processed.

In [25]:
result
Out[25]:
['0x00', '0x02', '0x04']
In [32]:
item['new']=[]
item['new']=["%s"% j for j in range(len(iu))]
item['new']
Out[32]:
['0', '1', '2', '3', '4']
In [34]:
item['new']=["None" for j in range(len(iu))]
In [35]:
item['new']
Out[35]:
['None', 'None', 'None', 'None', 'None']

Оказывается, что можно задать вот такой список из пустых строк

In [36]:
item['new']=[]
item['new']=["" for j in range(len(iu))]
item['new']
Out[36]:
['', '', '', '', '']
In [37]:
item['new']=[]
item['new']=["WoW" for j in range(len(iu))]
item['new']
Out[37]:
['WoW', 'WoW', 'WoW', 'WoW', 'WoW']

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

In [38]:
item['supernew']=["WoWa" for j in range(len(iu))]

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

In [39]:
item['supernew']
Out[39]:
['WoWa', 'WoWa', 'WoWa', 'WoWa', 'WoWa']

Вот он какой - этот новый словарь:

In [40]:
item
Out[40]:
{'new': ['WoW', 'WoW', 'WoW', 'WoW', 'WoW'],
 'oth': ['oth1', 'oth2', 'oth3', 'oth4', 'oth5'],
 'supernew': ['WoWa', 'WoWa', 'WoWa', 'WoWa', 'WoWa'],
 'url': ['url1', 'url2', 'url3', 'url4', 'url5']}
In [15]:
help(iu)
Help on list object:

class list(object)
 |  list() -> new empty list
 |  list(iterable) -> new list initialized from iterable's items
 |  
 |  Methods defined here:
 |  
 |  __add__(...)
 |      x.__add__(y) <==> x+y
 |  
 |  __contains__(...)
 |      x.__contains__(y) <==> y in x
 |  
 |  __delitem__(...)
 |      x.__delitem__(y) <==> del x[y]
 |  
 |  __delslice__(...)
 |      x.__delslice__(i, j) <==> del x[i:j]
 |      
 |      Use of negative indices is not supported.
 |  
 |  __eq__(...)
 |      x.__eq__(y) <==> x==y
 |  
 |  __ge__(...)
 |      x.__ge__(y) <==> x>=y
 |  
 |  __getattribute__(...)
 |      x.__getattribute__('name') <==> x.name
 |  
 |  __getitem__(...)
 |      x.__getitem__(y) <==> x[y]
 |  
 |  __getslice__(...)
 |      x.__getslice__(i, j) <==> x[i:j]
 |      
 |      Use of negative indices is not supported.
 |  
 |  __gt__(...)
 |      x.__gt__(y) <==> x>y
 |  
 |  __iadd__(...)
 |      x.__iadd__(y) <==> x+=y
 |  
 |  __imul__(...)
 |      x.__imul__(y) <==> x*=y
 |  
 |  __init__(...)
 |      x.__init__(...) initializes x; see help(type(x)) for signature
 |  
 |  __iter__(...)
 |      x.__iter__() <==> iter(x)
 |  
 |  __le__(...)
 |      x.__le__(y) <==> x<=y
 |  
 |  __len__(...)
 |      x.__len__() <==> len(x)
 |  
 |  __lt__(...)
 |      x.__lt__(y) <==> x<y
 |  
 |  __mul__(...)
 |      x.__mul__(n) <==> x*n
 |  
 |  __ne__(...)
 |      x.__ne__(y) <==> x!=y
 |  
 |  __repr__(...)
 |      x.__repr__() <==> repr(x)
 |  
 |  __reversed__(...)
 |      L.__reversed__() -- return a reverse iterator over the list
 |  
 |  __rmul__(...)
 |      x.__rmul__(n) <==> n*x
 |  
 |  __setitem__(...)
 |      x.__setitem__(i, y) <==> x[i]=y
 |  
 |  __setslice__(...)
 |      x.__setslice__(i, j, y) <==> x[i:j]=y
 |      
 |      Use  of negative indices is not supported.
 |  
 |  __sizeof__(...)
 |      L.__sizeof__() -- size of L in memory, in bytes
 |  
 |  append(...)
 |      L.append(object) -- append object to end
 |  
 |  count(...)
 |      L.count(value) -> integer -- return number of occurrences of value
 |  
 |  extend(...)
 |      L.extend(iterable) -- extend list by appending elements from the iterable
 |  
 |  index(...)
 |      L.index(value, [start, [stop]]) -> integer -- return first index of value.
 |      Raises ValueError if the value is not present.
 |  
 |  insert(...)
 |      L.insert(index, object) -- insert object before index
 |  
 |  pop(...)
 |      L.pop([index]) -> item -- remove and return item at index (default last).
 |      Raises IndexError if list is empty or index is out of range.
 |  
 |  remove(...)
 |      L.remove(value) -- remove first occurrence of value.
 |      Raises ValueError if the value is not present.
 |  
 |  reverse(...)
 |      L.reverse() -- reverse *IN PLACE*
 |  
 |  sort(...)
 |      L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
 |      cmp(x, y) -> -1, 0, 1
 |  
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |  
 |  __hash__ = None
 |  
 |  __new__ = <built-in method __new__ of type object>
 |      T.__new__(S, ...) -> a new object with type S, a subtype of T




Посты чуть ниже также могут вас заинтересовать

Комментариев нет:

Отправить комментарий