Как стать автором
Обновить

Комментарии 25

Ответил на все вопросы. Даже на тот, который помечен как «крутой ответ». А макбук не дали. Оказывается, в оферте было написано, что приз даётся победителю викторины. При этом перед началом тестирования большими буквами: «Пройди тест и выиграй макбук». Начинать возможное сотрудничество с нехитрого обмана некомильфо, господа. Вы же не юриста нанимали на работу.
«Пройди тест и выиграй макбук» — подразумевает именно, что его надо выиграть, а именно дать наиболее полный, внятный и развернутый ответ. Таких же участников, который давали свои ответы на викторину — не один десяток. В условиях конкуренции, я допускаю, что был кто-то, кто дал наиболее интересные ответы. Это как: «участвуй в конкурсе и выиграй квартиру», всем что ли участникам должны дать квартиру?
===
Отправитель: **** <***@ostrovok.ru>
Добрый день!
Мы благодарим Вас за участие в конкурсе от Островка!
К выполнению задания приступало более пятисот человек! И, к нашей и,
надеемся, Вашей радости тоже, Вы оказались одним из лучших!
Нам хотелось бы продолжить диалог и пригласить Вас на встречу!
===
Отправитель: **** <***@ostrovok.ru>
Александр, Вы принимали участие в Конкурсе на соискание работы в Островке.
Материальные призы разыгрывались в Викторине.
===
Речь о том, что макбук вообще не в тесте разыгрывался. И об этом было написано только в оферте.
Можно ваш email, мне в личку, я буду разбираться с этим.
Вроде ответил на вопросы :)
А вы можете прислать ответы, которые я дал?)) (а то это было поздно ночью)
Нет, это всё и так понятно и с Гуглом все дружат. А вы можете просто запостить целиком все ответы человека, показавшегося вам самым-самым? Не с точки зрения разборок (я вообще не участвовал), а для интереса. Вдруг там какие хорошие и необычные мысли проскакивали?
Я выложу свои ответы под этим комментарием, когда вернусь домой, если ребята с Островка не сделают это раньше. Сейчас под рукой просто нет сохраненной копии.
1. При помощи процессов. Особенности:
= Изолированное адресное пространство.
= Примитивы межпроцессного взаимодействия (именованные (FIFO)/неименованные каналы, семафоры, очереди сообщений, разделяемая память, сокеты, STREAMS) и программные прерывания из signal.h (POSIX.1).

2. При помощи потоков (те, что threads). Особенности:
= Разделяемое адресное пространство (как следствие — просто организовать совместный доступ к памяти и файловым дескрипторам).
= Примитивы синхронизации потоков / согласованного доступа к разделяемым ресурсам (мьютексы, совместно-исключающие блокировки (rwlocks)).

3. Различные реализации green threads/processes, которые по-сути пытаются комбинировать “удачные” подходы (например – изоляция и время на порождение) двух предыдущих подходов, выполняясь в userspace внутри какой-нибудь виртуальной машины.

Мне сложно формализовать ответ в виде списка преимуществ/недостатков. Попробую описать субъективную точку зрения.

Если взять некий абстрактный однопоточный процесс, выполняющий несколько независимых операций последовательно, и сравнить его с процессом, в котором те же самые задачи выполняются в несколько потоков, то в таком же общем абстрактном случае, первый процесс будет иметь меньшую производительность.
Ещё одно “абстрактное преимущество” — можно упростить обработку асинхронных событий, привязав отдельный тип события к отдельному потоку. Сам поток при этом может быть написан с использованием обычного синхронного подхода.
Но это очень грубое обобщение. Если оно ещё работает в каких-нибудь интерактивных программах вроде текстового редактора, где вполне логично выделять в отдельный поток обработку пользовательского ввода-вывода от других компонентов редактора, то в более сложных системах (вроде реляционных СУБД) предпочтительный подход и его плюсы/минусы не так очевидны.

В сложных системах иногда лучше ввязываться в использование IPC и идти на компромисс в производительности (не такой ощутимый, впрочем), чем усложнять логику дополнительными механизмами синхронизации потоков. Достаточно сравнить исходные тексты обработчиков соединений в MySQL (многопоточный подход) и Postgres (межпроцессный подход).
Если снова прибегнуть к обобщениям, то отлаживать многопоточный компонент сложнее, он чреват на неявные ошибки, из-за которых страдает “надёжность” всего процесса (родительского потока).

========================================

O(n*log(n))

Если порядок элементов не важен, то
def uniq(iterable):
    return list(set(iterable))


Если порядок важен, то
def uniq(iterable):
    selected = set() 
    return [item for item in iterable if (item not in selected and not selected.add(item))]


========================================

Умножение списка ([] * N) фактически выполняет операцию “мягкого” копирования каждого элемента списка в N экземпляров, при котором в списке создаются не новые объекты с одинаковыми значениями, а “метки” на оригинальные объекты (можно их назвать указателями/ссылками, но это не то же самое, что указатели/ссылки в C/C++).
>>> a = range(3) * 2 
>>> a 
[0, 1, 2, 0, 1, 2] 
>>> a[0] 
0 
>>> a[3] 
0 
>>> id(a[0]) == id(a[3]) 
True 


Простые типы в Python являются неизменяемыми (immutable) объектами, поэтому, при попытке изменения значения, на которое указывает “метка” a[0], фактически будет создан новый объект с новым значением, к которому будет привязана старая метка.
>>> a[0] = 1 
>>> id(a[0]) == id(a[3]) 
False 


Списки же, являются изменяемыми объектами, поэтому когда мы изменяем состав элементов в a[0], этот объект не замещается новым. Поэтому мы видим все изменения объекта и через метку a[0], и через метку a[1].
>>> a = [range(3)] * 2 
>>> a 
[[0, 1, 2], [0, 1, 2]] 
>>> id(a[0]) == id(a[1]) 
True 
>>> id(a[0][0]) == id(a[1][0]) 
True 
>>> a[0][0] = 1 
>>> a 
[[1, 1, 2], [1, 1, 2]] 
>>> id(a[0]) == id(a[1]) 
True 
>>> id(a[0][0]) == id(a[1][0]) 
True


Однако, элементы внутри вложенного списка всё так же замещаются, т.к. являются простыми:
>>> a 
[[1, 1, 2], [1, 1, 2]] 
>>> id(a[0][0]) == id(a[1][0]) 
True 
>>> b=a[0][0] 
>>> id(b) == id(a[1][0]) 
True 
>>> a[0][0] = 10 
>>> a 
[[10, 1, 2], [10, 1, 2]] 
>>> b 
1 
>>> id(b) == id(a[1][0]) 
False 


========================================

Всё дело в метаданных объектов Python.
point = Point()
dir(point)
dir(point.x)

Первоначальная оптимизация может заключаться в использовании array.array. Затем можно будет поискать возможные способы для группирования наборов точек в более крупные объекты, с меньшим количеством самостоятельных объектов-координат. Всё же, редко когда нам нужна именно отдельно взятая точка.
Возможный начальный вариант объекта-точки с использованием array.array может выглядеть так:

from array import array

class Point(object):
	_coord_mapping = {'x':0, 'y':1, 'z':2}
	
	def __init__(self, xyz_list, type_code='f'):
		"""The type of elements of `xyz_list(count:3)` must correspond to 
		`type_code`."""
		object.__setattr__(self, '_container', array(type_code, xyz_list))
		
	def __getattribute__(self, key):
		get_attr = object.__getattribute__
		if key not in get_attr(self, '_coord_mapping'):
			raise AttributeError('Unable to get the "{}" coordinate.'.format(key))
		return get_attr(self, '_container')[get_attr(self, '_coord_mapping')[key]]
	
	def __setattr__(self, key, val):
		get_attr = object.__getattribute__
		if key not in get_attr(self, '_coord_mapping'):
			raise AttributeError('Unable to set the "{}" coordinate.'.format(key))
		get_attr(self, '_container')[get_attr(self, '_coord_mapping')[key]] = val
	
	def __repr__(self):
		coords = object.__getattribute__(self, '_container')
		return "Point({}, {}, {})".format(coords[0], coords[1], coords[2])


Пример:
>>> point = Point([1,2,3], 'f') 
>>> point 
Point(1.0, 2.0, 3.0) 
>>> point.x 
1.0 
>>> point.y 
2.0 
>>> point.z 
3.0 
>>> point.x = 5 
>>> point.y = 6 
>>> point.z = 7 
>>> point 
Point(5.0, 6.0, 7.0)


========================================

Это связяано со способом представления рациональных чисел в ЭВМ в бинарном виде (конкретно, согласно стандарту IEEE-754). В принципе, любой студент, писавший в университете на Паскале в курсе, что сравнивать числа с плавающей точкой (запятой?) можно только в пределах заданной точности. Т.е. в простейшем случае — выполнять сравнение между разницей двух чисел и точностью:
>>> a=0.01 
>>> b=0.1 
>>> c = a + 0.09 
>>> c 
0.09999999999999999 
>>> c == b 
False 
>>> abs(c - b) 
1.3877787807814457e-17 
>>> abs(c - b) <= 0.001 
True 
>>> abs(c - b) <= 0.000001 
True 
>>> abs(c - b) <= 0.0000001 
True 
>>> abs(c - b) <= 0.00000001 
True 
>>> abs(c - b) <= 0.000000001 
True 
>>> abs(c - b) <= 0.0000000001 
True 
>>> abs(c - b) <= 0.00000000001 
True 
>>> abs(c - b) <= 0.000000000001 
True 
>>> abs(c - b) <= 0.0000000000001 
True 
>>> abs(c - b) <= 0.00000000000001 
True 
>>> abs(c - b) <= 0.000000000000001 
True 
>>> abs(c - b) <= 0.0000000000000001 
True 
>>> abs(c - b) <= 0.00000000000000001 
False 
>>> abs(c - b) <= 0.000000000000000001 
False 


В стандартной библиотеке Python, однако, уже есть реализация decimal-чисел (чисел с фиксированной десятичной точкой), поэтому пример можно переписать так:
from decimal import *
getcontext().prec = 2

def add1Cent(sum):
	return sum + Decimal('0.01')

s = Decimal('0.00')
for i in range(5):
	s = add1Cent(s)
	
# now I have 5 cents!
print s == Decimal('0.05')

# ok, lets add another five!
for i in range(5):
	s = add1Cent(s)

# now I have 10!
print s == Decimal('0.1')
print s > Decimal('0.1')
print s < Decimal('0.1')


=======================================

Вопрос не совсем понятен.
Если это csv-файл, то там должны быть переводы строк. Любая конструкция вида for line in file – уже использует “ленивое” чтение строк из таких файлов.
Правда, файл может состоять из одной большой строки. Тогда можно организовать чтение файла по кускам, но в таком случае, обработка csv-строки в таком виде, как она представлена в примере – невозможна.

Поэтому, я бы оставил текущий алгоритм, но добавил бы в него with для безопасного и явного закрытия дескриптора:
total = 0
with open('somefile.csv') as file:
    for line in file:
        csv_list = line.split(',')
        if csv_list[5]:
            total += int(csv_list[5])
print "Всего: ", total


Собственно, преимущества генераторов сводятся к более эффективному потреблению памяти, т.к. во многих итеративных алгоритмах нам не нужно хранить всю коллекцию обрабатываемых данных в памяти на протяжении всего времени.
А, например, при обработке небольших файлов в среде, где есть “гонка за ресурсами”, скорее всего будет выгоднее прочитать файл целиком и пораньше освободить файловый дескриптор, чем использовать генераторы.

=======================================

Разница в формате представления строк в памяти программы. Если речь о Python 2.x, то стандартное 'фыва' – это 8-битное ASCII-представление (литерал) строк, которое в программе представлено как <type 'str'>. u'фыва' – формат для представления в исходниках литералов юникодных строк. В памяти они хранятся как последовательности из 16 или 32-битных чисел (зависит от сборки и реализации интерпретатора). Когда исходник читается и выполняется интерпретатором, все u'' литералы фактически конструируются в памяти через вызов unicode('фыва', encoding), где encoding – кодировка исходного файла — примет либо значение по умолчанию (ASCII), либо значение, согласно магической последовательности -*- coding: -*-.
В Python 3 любой строковый литерал представлен в программе как юникодная строка и никакого явного разделения на уровне типов нет. Бинарные данные – отдельный тип.

> где и почему это важно?

Как и везде – важно разделять, понимать, и использовать по назначению. Правда, “использовать по назначению” не-юникодные строки или не utf-* исходники в современном мире довольно странно.

=======================================

class B(A):
    def __init__(self):
        super(B, self).__init__()
        print "init in B"


либо

class B(A):
    def __init__(self):
        A.__init__(self)
	print "init in B"


Правда, первый вариант в данном примере лучше.
Но круче:
def uniq(iterable):
  result = list(set(iterable))


Это не круче. Из названия функции не понятно, что она должен обязательно возвращать список. Лучше просто использовать set там, где нужны только уникальные значения, и не придумывать бессмысленных функций.
Еще не сказано, существенен ли порядок элементов в результирующем списке?
Если нет, то еще один быстрый способ
{}.fromkeys(iterable).keys()

Могу запостить как я отвечал. По крайней мере, на собеседование меня после этого пригласили))
Кстати, чтоб немного потешить самолюбие ^_^ — правда что на собеседование приглашали только 5 человек из ~500 кандидатов?
Ну цифры примерно такого порядка.
Будет здорово если запостите.
Вопрос 1:
Какие есть методы организации параллельных вычислений, какие преимущества и недостатки каждого метода?
---
Не совсем понял что здесь подразумевается… То ли методологии и алгоритмы (MapReduce etc), то ли процессы vs потоки… Судя по размеру окошка для ответа, подразумевается все-же второе)
Можно выполнять параллельные вычисления с взаимодействием через разделяемой памятью (потоки), можно через отправку сообщений (процессы ОС). Первое обычно быстрее т.к. быстрее работает обращение к разделяемой памяти, но возникает множество пробем:
1) race confitions. Одновременный доступ к данным. Приходится использовать различные блокировки/мьютексы/очереди отсюда вытекает проблема 2:
2) Deadlock's — взаимные блокировки.
3) В случае краха одного из потоков, скорее всего упадет вся программа.
4) Высокие накладные расходы на переключение контекста
При взаимодействии через отправку сообщений как правило лишаемся тех недостатков. Распараллеливание на несколько компьютеров (по сети) заметно облегчается. Из минусов — оверхед на передачу сообщений, на сериализацию и копирование данных.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вопрос 2:
Оцените сложность алгоритма и предложите варианты по улучшению:
def uniq(iterable): 
    result = []
    for i in iterable: 
        if i not in result: 
            result.append(i)


---

WTF? Это-ж задание с яндексовских вакансий! Причем переделано не совсем корректно ибо не указано какого типа данные в i. Предположим, что строки.
Судя по тому, что функция ничего не возвращает, можно заменить ее на
`def uniq(iterable): pass`
Точно так же будет возвращать None)))
Ладно, сарказм в сторону, переходим к делу!
Основная проблема которую я вижу — это конструкция «i not in result». У нее временная сложность O(n) согласно wiki.python.org/moin/TimeComplexity. Сложность итерации — O(n). Т. е. суммарная сложность будет O(n^2).
Предположили, что элементы являются строками, т.е. они немутабельны и хешируемы. Соответственно, можно использовать дополнительное хранилище найденных уникальных токенов в виде set() объекта и использовать его для проверки дубликатов. У операции `i in _found`, где "_found" — это set, сложность O(1), у операции вставки в set сложность так же O(1). Тогда суммарная сложность алгоритма будет O(n). Но при этом получаем небольшой оверхед по памяти для хранения структуры set-а.
def uniq(iterable):
	result = []
	_found=set()
	for i in iterable:
		if i not in _found:
			_found.add(i)
			result.append(i)


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вопрос 3:
В чем разница и почему так:
>>> a = range(3) * 2
>>> print a
[0, 1, 2, 0, 1, 2]
>>> a[0] = 1
>>> a
[1, 1, 2, 0, 1, 2]
>>> a = [range(3)] * 2
>>> print a
[[0, 1, 2], [0, 1, 2]]
>>> a[0][0] = 1
>>> a
[[1, 1, 2], [1, 1, 2]]


---

в первом случае создается список `[0, 1, 2]`, создается 2 его неполных — shallow(!!!) копии. И затем списки конкатенируются. При shallow — копировании контейнера создается новый объект такого же типа и в него вставляются ссылки(!!!) на содержимое копируемого контейнера.
Первое выражение эквивалентно
l=[0, 1, 2]
a=l+l

второе
l=[[0, 1, 2]]
a=l+l

В первом случае в `a` содержатся неизменяемые (immutable) данные — числа. Во втором — две ссылки на один и тот же объект — список `[0, 1, 2]`. Для второго случая даже будет верно
`assert id(a[0])==id(a[1])`

Таким образом, в строке
`a[0][0] = 1`
мы:
1) `a[0]` — получаем ссылку на единственный объект — список `[1, 2, 3]` (ссылка на него хранится в `a`)
2) `a[0][0] = 1` — в полученном объекте — списке заменяем нулевой элемент на единицу.

Как-то так…

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вопрос 4:
Мы придумали свой класс Point для хранения координат и примитивных операций над ними. Выглядит примерно так:
class Point(): 
    def __init__(self): 
        self.x = None
        self.y = None
        self.z = None
        ...

Потом обнаружили, что программа, оперирующая большим количеством экземпляров такого класса ест много памяти. Миллион таких объектов занимает минимум 360мб. Что занимает так много памяти и как можно улучшить ситуацию?

---

В Python по умолчанию для каждого экземпляра класса создается служебный параметр `__dict__` для хранения собственных атрибутов объекта. Этот `__dict__` представляет из себя обычный питоний словарь. Но для хранения словаря нужна память. Например, для хранения пустого словаря расходуется около 136 байт на x86 и 280 байт на x64:
>>> import sys
>>> sys.getsizeof({})
280

Для борьбы с этим оверхедом для new-style классов ввели атрибут __slots__. Этот атрибут представляет из себя кортеж, в котором перечислены имена всех атрибутов объекта. Так, Point можно переписать как
class GoodPoint(object):
    __slots__=('x', 'y', 'z')#, ...)
    def __init__(self): 
        self.x = None
        self.y = None
        self.z = None
        ...

Попробовал на своем десктопе — без __slots__ интерпретатор со списком из миллиона точек занимает 180Мб памяти, со __slots__ всего 42Мб

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вопрос 5:
Что происходит? Кто виноват? Что делать?
>>> def add1Cent(sum):
...     return sum + 0.01
... 
>>> s = 0
>>> for i in range(5):
...     s = add1Cent(s)
... 
>>> # now I have 5 cents!
>>> print s == 0.05
True
>>> # ok, lets add another five!
>>> for i in range(5):
...     s = add1Cent(s)
... 
>>> # now I have 10!
>>> print s == 0.1
False
>>> print s > 0.1
False
>>> print s < 0.1
True


---

Побочный эффект арифметических операций над числами с плавающей точкой. Точность недостаточно высокая. Нужно использовать int или decimal. Судя по всему, это функция для работы с деньгами, тогда лучше брать decimal.Decimal.
>>> import decimal
>>> decimal.getcontext().prec = 8
>>>def add1Cent(sum):
...    return sum+decimal.Decimal('0.01')
...
>>> for i in range(10):
...     s = add1Cent(s)
Decimal('0.10')


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вопрос 6:
Перепишите следующий код с использованием генераторов
file = open('somefile.csv')
total = 0
for line in file:
    csv_list = line.split(',')
    if csv_list[5]:
         total += int(csv_list[5])
            
print "Всего: ", total

Какие плюсы у получившегося кода? Какие минусы?

---

Очень сомнительная идея — использовать тут генераторы. По-моему текущая версия и так самая простая, понятная и правильная.
Но для начала замечу, что парсить CSV таким образом не стоит. Для этого существует хороший встроенный модуль `csv`…

with open('somefile.csv', 'r') as file:
    column5gen=(line.split(',')[5] for line in file)
    total=sum(int© for c in column5gen if c)


Из плюсов — уместили алгоритм в 2 строчки вместо 4-х. Можно и в одну впихнуть, но кому это надо? Из минусов — заметно труднее понять что этот код делает. Производительность и расход памяти примерно одинаковые должны быть. Возможно небольшой оверхед на заморозку контекста генератора…

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вопрос 7:
В чем разница между 'фыва' и u'фыва'? где и почему это важно?

---

'фыва' — это объект — строка (str), а u'фыва' — объект юникодная строка (unicode). Один символ в str занимает обычно 8 бит, в unicode — завимит от реализации. Если обычная str строка содержит НЕлатинские символы, то эта строка кодированная в какой-либо кодировке (utf8/cp1251/latin1 etc). При работе со str всегда нужно держать в голове в какой именно кодировке строка, иначе могут возникунуть проблемы при обработке этой строки (печати, сохранении в БД, запихивании в XML/JSON etc). Если в тексте программы используются строковые константы в виде str, например logging.info(«Случилось что-то хорошее!»), то эта строка будет в той кодировке, в которой сохранен файл с исходником программы — при пересохранении в Linux/Windows могут появиться проблемы… Внутри программы лучше повсеместно использовать unicode строки, конвертируя их сразу при получении от IO источников.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Вопрос 8:
Как переписать код, чтобы в конструкторе B запускался и коснтруктор класса A?
class A:
    def __init__(self):
        print "init in A"
            
class B(A):
    def __init__(self):
        print "init in B"
            
>>> b = B()
init in B


---

Странный вопрос…
class A:
    def __init__(self):
        print "init in A"
            
class B(A):
    def __init__(self):
        print "init in B"
        super(B, self).__init__()
Только сегодня осознал что на последний вопрос неправильно ответил для old-style классов. Когда решал задания долго искал подвох но не нашел.
Спасибо.
> Вопрос 6. Перепишите следующий код с использованием генераторов
>… мы ждали чего-то вроде:
Генератор — это вроде как «yield», а у вас в ответе итераторы…
Да и вообще очень размытое задание.
Вы правы, мы ожидали увидеть Generator Expression а не Generator, но это никак не повлияло на выбор лучших.
> Строка в кодировке Unicode. Эта кодировка поддерживает все существующие языки и символы. Выгода, применения такой кодировки, для работы с данными очевидна. Например, для многоязычных приложений.
Многоязычные приложения могут работать и на utf-8. Соль не в этом.

> Некоторые функции python конвертируют строки в кодировку указанную по умолчанию, например print().
print не конвертирует кодировку, этим занимается sys.stdout
Полазил по сайту, ничего пока интересного и нового не нашел. Можете рассказать, в чем уникальность Островка, что отличает его от других сайтов?..
И после историй с Сони, как то стремно вводить номер кредитки у вас на сайте. Сделайте оплату через именитые биллинги, к примеру PayPal и т.д.
Я так понимаю, что базу отелей вы используете с travelnow.com?
Т.е. получается, вы являетесь посредником travelnow.com в России?
Немножко пожалуюсь тоже

1) Некоторые вопросы были неоднозначны или не совсем точно сформулированы. Например под «способами организации параллельных вычислений» можно разные вещи понимать… То ли меня просят про Map-reduce рассказать, то ли про процессы vs потоки
2) Вопрос #2 вообще немного удивил. Может это и случайность, но ооочень похожий есть в вакансиях яндекса company.yandex.ru/job/vacancies/dev_mail_pyt.xml и там он сформулирован более корректно. Например, указывается что итератор возвращает строки. Если бы он возвращал mutable- данные (словари/списки), то в set его было бы бессмысленно засовывать т.к. они нехешируемые. Ну и то, что функция uniq() не возвращает результат повеселило.
Кстати, в вашем решении
total = sum(int(line.split(',')[5]) for line in open('somefile.csv') if line.split(',')[5])
падение производительности может вырасти и не на 30% а на бесконечно много, если в строках будет много значений разделенных запятыми — из за того что вы 2 раза делаете line.split() (один раз в int(), другой раз в if)

Ну а в целом, спасибо за конкурс — было интересно принять участие. И офис у вас классный (особенно сушилка для рук в туалете xD) и пообщались на собеседовании интересно.
Все строки в python по умолчанию кодируются в ASCII (именно поэтому при компиляции возникает проблема, если строка сожержит не ASCII символ).
Неправда ваша, в Python 3.x все строки — Unicode, кодируются в UTF-8, если не указана другая кодировка в файле. Кроме того существует возможность сменить кодировку по-умолчанию для всего python environment любой версии, правда это из области грязных хаков.
Про uniq через set уже сказали — результат-то другой будет, чем в исходном алгоритме.

class Point(object):
	__slots__=('a', 'b', 'c')
	def __init__(self): 
		self.a = None
		self.b = None
		self.c = None

Вместо __slots__ для данного примера в 2.6+ лучше, наверное, использовать namedtuple.

total = sum(int(line.split(',')[5]) for line in open('somefile.csv') if line.split(',')[5])

Этот код полагается на детали реализации сборщика мусора в CPython, лучше так не писать и файлы открывать всегда через with, т.к. в других реализациях (том же pypy) файловый дескриптор останется болтаться.

u'фыва' # строка закодированная в unicode.

Строка в кодировке Unicode. Эта кодировка поддерживает все существующие языки и символы. Выгода, применения такой кодировки, для работы с данными очевидна. Например, для многоязычных приложений.

Принципиальное отличие 'foo' от u'foo' как раз в том, что юникод — это не кодировка.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий