print dir(Foo)
-
В Python для обозначения protected атрибутов используют
_
, для private —__
перед названием переменной.print [arg for arg in dir(Foo) if not arg.startswith('_')]
Public — доступ открыт всем, кто видит определение данного класса.
Private — доступ открыт самому классу (т.е. функциям-членам данного класса) и друзьям (friend) данного класса, как функциям, так и классам.
Protected — доступ открыт классам, производным от данного.
- В атрибуте
__doc__
. -
[:]
— обозначение среза в питоне. Про них можно почитать, например, тут. В кратце:[:]
создает копию lst и изменения в первом никак не влияют на итерацию по исходным значениям. -
Есть два списка одинаковой длины, в одном ключи, в другом значения.Составить словарь. Будем использовать функцию
zip
, которая делает кортежи из пары значений иdict
, которая создает словарь из переданных аргументов.a = ('John', 'Peter') b = (1, 2) print dict(zip(a, b))
- Python есть базовые структуры данных, типа tuple, list, dict, set Список это обьект или запись которая имеет ссылку на адрес следующего и предыдущего элемента и поле для хранения значения. tuple(Кортеж), по сути - неизменяемый список. Set — множество, в котором отсутствуют повторяющиеся элементы
-
- Прикладной уровень
- Уровень представления
- Сеансовый уровень
- Транспортный уровень
- Сетевой уровень
- Канальный уровень
- Физический уровень
-
Стек протоколов TCP/IP включает в себя четыре уровня:
- Прикладной уровень
На прикладном уровне (Application layer) работает большинство сетевых приложений. Эти программы имеют свои собственные протоколы обмена информацией, например, HTTP для WWW, FTP (передача файлов), SMTP (электронная почта), SSH (безопасное соединение с удалённой машиной), DNS (преобразование символьных имён в IP-адреса) и многие другие.
- Транспортный уровень
TCP (IP идентификатор 6) — «гарантированный» транспортный механизм с предварительным установлением соединения, предоставляющий приложению надёжный поток данных, дающий уверенность в безошибочности получаемых данных, перезапрашивающий данные в случае потери и устраняющий дублирование данных. UDP (IP идентификатор 17) протокол передачи датаграмм без установления соединения. Также его называют протоколом «ненадёжной» передачи, в смысле невозможности удостовериться в доставке сообщения адресату, а также возможного перемешивания пакетов.
- Сетевой уровень
Сетевой уровень (Internet layer) изначально разработан для передачи данных из одной (под)сети в другую.
- Канальный уровень
Канальный уровень (Link layer) описывает, каким образом передаются пакеты данных через физический уровень, включая кодирование (то есть специальные последовательности бит, определяющих начало и конец пакета данных).
- Cтандарт кодирования символов, позволяющий представить знаки почти всех письменных языков
-
def div1(x,y): print "%s/%s = %s" % (x, y, x/y) def div2(x,y): print "%s//%s = %s" % (x, y, x//y) div1(5,2) div1(5.,2) div2(5,2) div2(5.,2.)
In Python 2, the output of the above code will be:
5/2 = 2 5.0/2 = 2.5 5//2 = 2 5.0//2.0 = 2.0
By default, Python 2 automatically performs integer arithmetic if both operands are integers. As a result,
5/2 yields 2, while 5./2 yields 2.5
. Note that you can override this behavior in Python 2 by adding the following import:from __future__ import division
Also note that the “double-slash” (
//
) operator will always perform integer division, regardless of the operand types. That’s why 5.0//2.0 yields 2.0
even in Python 2.Python 3, however, does not have this behavior; i.e., it does not perform integer arithmetic if both operands are integers. Therefore, in Python 3, the output will be as follows:
5/2 = 2.5 5.0/2 = 2.5 5//2 = 2 5.0//2.0 = 2.0
-
def extendList(val, list=[]): list.append(val) return list list1 = extendList(10) list2 = extendList(123,[]) list3 = extendList('a') print "list1 = %s" % list1 print "list2 = %s" % list2 print "list3 = %s" % list3
The output of the above code will be:
list1 = [10, 'a'] list2 = [123] list3 = [10, 'a']
Many will mistakenly expect list1 to be equal to [10] and list3 to be equal to [‘a’], thinking that the list argument will be set to its default value of [] each time extendList is called.
However, what actually happens is that the new default list is created only once when the function is defined, and that same list is then used subsequently whenever extendList is invoked without a list argument being specified. This is because expressions in default arguments are calculated when the function is defined, not when it’s called. list1 and list3 are therefore operating on the same default list, whereas list2 is operating on a separate list that it created (by passing its own empty list as the value for the list parameter). The definition of the extendList function could be modified as follows, though, to always begin a new list when no list argument is specified, which is more likely to have been the desired behavior:
def extendList(val, list=None): if list is None: list = [] list.append(val) return list
With this revised implementation, the output would be:
list1 = [10] list2 = [123] list3 = ['a']
-
class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print Parent.x, Child1.x, Child2.x Child1.x = 2 print Parent.x, Child1.x, Child2.x Parent.x = 3 print Parent.x, Child1.x, Child2.x
The output of the above code will be:
1 1 1 1 2 1 3 2 3
What confuses or surprises many about this is that the last line of output is
3 2 3
rather than3 2 1
. Why does changing the value ofParent.x
also change the value of Child2.x, but at the same time not change the value ofChild1.x
?The key to the answer is that, in Python, class variables are internally handled as dictionaries. If a variable name is not found in the dictionary of the current class, the class hierarchy (i.e., its parent classes) are searched until the referenced variable name is found (if the referenced variable name is not found in the class itself or anywhere in its hierarchy, an AttributeError occurs). Therefore, setting x = 1 in the Parent class makes the class variable x (with a value of 1) referenceable in that class and any of its children. That’s why the first print statement outputs 1 1 1. Subsequently, if any of its child classes overrides that value (for example, when we execute the statement Child1.x = 2), then the value is changed in that child only. That’s why the second print statement outputs 1 2 1. Finally, if the value is then changed in the Parent (for example, when we execute the statement Parent.x = 3), that change is reflected also by any children that have not yet overridden the value (which in this case would be Child2). That’s why the third print statement outputs 3 2 3.
-
def f(a=[]): a.append(1) return a a=(f(),f())
Ответ:
а = ([1,1], [1,1])
Default values are calculated, once, when the function is defined; thus, a mutable object such as a list or dictionary used as default value will be shared by all calls that don’t specify an argument value for the corresponding slot; this should usually be avoided..
-
Запущенная на Python программа называется процессом. Процесс при запуске содержит один единственный поток, который обычно называют главным потоком процесса. Поток последовательно выполняет инструкции программного кода.
Процесс содержит информацию об объеме занимаемой оперативной памяти, списке открытых файлов, программный счетчик ссылающийся на выполняемую инструкцию, стек вызовов используемый для хранения локальных переменных функции.
Программа может создавать новые процессы, называемые — дочерними. Дочерние процессы являются независимыми и изолированными друг от друга. У процесса существует флаг, говорящий о том, является ли процесс демоническим. Демонический процесс автоматически завершается вместе с процессом создавшим его, кроме того демонические процессы не могут создавать дочерних.
Если нужно, чтобы ваше приложение выполняло несколько задач в одно и то же время, то можете воспользоваться потоками (threads). Потоки позволяют приложениям выполнять в одно и то же время множество задач. Многопоточность (multi-threading) важна во множестве приложений, от примитивных серверов до современных сложных и ресурсоёмких игр. Когда в одной программе работают несколько потоков, возникает проблема разграничения доступа потоков к общим данным. Предположим, что есть два потока, имеющих доступ к общему списку. Первый поток может делать итерацию по этому списку: for x in L а второй в этот момент начнет удалять значения из этого списка. Тут может произойти все что угодно: программа может упасть, или мы просто получим неверные данные. Решением в этом случае является применение блокировки. При этом доступ к заблокированному списку будет иметь только один поток, второй будет ждать, пока блокировка не будет снята. Применение блокировки порождает другую проблему – дедлок (deadlock) – мертвая блокировка. Пример дедлока: имеется два потока и два списка. Первый поток блокирует первый список, второй поток блокирует второй список. Первый поток изнутри первой блокировки пытается получить доступ к уже заблокированному второму списку, второй поток пытается проделать то же самое с первым списком. Получается неопределенная ситуация с бесконечным ожиданием. Эту ситуации легко описать, на практике все гораздо сложнее. Вариантом решения проблемы дедлоков является политика определения очередности блокировок. Например, в предыдущем примере мы должны определить, что блокировка первого списка идет всегда первой, а уже потом идет блокировка второго списка. Другая проблема с блокировками – в том, что несколько потоков могут одновременно ждать доступа к уже заблокированному ресурсу и при этом ничего не делать. Каждая питоновская программа всегда имеет главный управляющий поток. Питоновская реализация многопоточности ограниченная. Интерпретатор питона использует внутренний глобальный блокировщик (GIL), который позволяет выполняться только одному потоку. Это сводит на нет преимущества многоядерной архитектуры процессоров. Для многопоточных приложений, которые работают в основном на дисковые операции чтения/записи, это не имеет особого значения, а для приложений, которые делят процессорное время между потоками, это является серьезным ограничением.
- Global Interpreter Lock (GIL) — это способ синхронизации потоков, который используется в некоторых интерпретируемых языках программирования, например в Python, Ruby и Java Script. GIL является самым простым способом избежать конфликтов при одновременном обращении разных потоков к одним и тем же участкам памяти]. Когда один поток захватывает его, GIL. Нет параллельных потоков — нет конфликтов при обращении к разделяемым объектам. Очередность выполнения потоков определяет интерпретатор, в зависимости от реализации, переключение между потоками может происходить: когда активный поток пытается осуществить ввод-вывод, по исчерпании лимита выполненных инструкций, либо по таймеру.
-
Итераторы используются для прохождения по какому-нибудь контейнеру без учета особенностей его внутреннего строения. Обычно итераторы используются в циклах типа «foreach»
В классах, реализующих итераторы, должны быть определены методы «iter()» и «next()». iter() возвращает ссылку на итерируемый объект-контейнер, а next() при каждом вызове должен возвращать следующий элемент и бросать исключение StopIteration, если все элементы уже обработаны.
По умолчанию, итераторы однонаправленные и не возобновляемые.
-
Генераторы — это «ленивые» итераторы — функции, возвращающие следующий элемент тогда, когда он запрашивается. В генераторах запоминается точка выхода из функции и при следующем обращении работа функции продолжается с места выхода.
Для создания генераторов используют функции, содержащие в своем теле ключевое слово «yield» — такие функции возвращают объект-генератор.
Генераторы занимают в памяти меньше места, чем списки, так как каждый раз в ячейке памяти хранится только один результат, когда список требует память для храниения всех своих значений.
-
Генерация списков (не знаю как адекватно перевести на русский list comprehensions) — яркий пример «синтаксического сахара». То есть конструкции, без которой легко можно обойтись, но с ней намного лучше :) Генераторы списков, как это не странно, предназначены для удобной обработки списков, к которой можно отнести и создание новых списков, и модификацию существующих. Допустим, нам необходимо получить список нечетных чисел, не превышающих 25. В принципе, только познакомившись с работой команды xrange решить эту проблему несложно.
>>> res = [] >>> for x in xrange(1, 25, 2): ... res.append(x) ... >>> print res
В общем-то, полученный результат — целиком нас устраивает всем, кроме длинной записи. тут-то на помощь и придет наш «сахарок». В самом простом виде, он обычно
>>> res = [x for x in xrange(1, 25, 2)] >>> print res [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23]
-
global
- позволяет изменять глобальные переменные внутри функции и присваивать их.X = 88 # Глобальная переменная X def func(): global X X = 99 # Глобальная переменная X: внутри инструкции def func() print(X) # Выведет 99
-
Три основные области видимости:
-
Если присваивание переменной выполняется внутри инструкции
def
, переменная является локальной для этой функции. -
Если присваивание производится в пределах объемлющей инструкции
def
, переменная является нелокальной для этой функции. -
Если присваивание производится за пределами всех инструкций
def
, она является глобальной для всего файла.
Функции образуют локальную область видимости, а модули – глобальную.
Эти две области взаимосвязаны между собой следующим образом:
-
Объемлющий модуль – это глобальная область видимости.Глобальные переменные для внешнего мира становятся атрибутами объекта модуля, но внутри модуля могут использоваться как простые переменные.
-
Глобальная область видимости охватывает единственный файл. Не надо заблуждаться насчет слова «глобальный» – имена на верхнем уровне файла являются глобальными только для программного кода в этом файле. Имена всегда относятся к какому-нибудь модулю и всегда необходимо явно импортировать модуль, чтобы иметь возможность использовать имена, определяемые в нем. Когда вы слышите слово «глобальный», подразумевайте «модуль».
-
Каждый вызов функции создает новую локальную область видимости. Всякий раз, когда вызывается функция, создается новая локальная область видимости – то есть пространство имен, в котором находятся имена, определяемые внутри функции. Каждую инструкцию
def
(и выражениеlambda
) можно представить себе, как определение новой локальной области видимости. -
Операция присваивания создает локальные имена, если они не были объявлены глобальными или нелокальными. По умолчанию все имена, которым присваиваются значения внутри функции, помещаются в локальную область видимости. Если необходимо присвоить значение имени верхнего уровня в модуле, который вмещает функцию, это имя необходимо объявить внутри функции глобальным с помощью инструкции
global
. Если необходимо присвоить значение имени, которое находится в объемлющей инструкцииdef
, в Python 3.0 это имя необходимо объявить внутри функции с помощью инструкцииnonlocal
. -
Все остальные имена являются локальными в области видимости объемлющей функции, глобальными или встроенными.
-
-
Функции
map
,zip
и лямбда (кстати говоря называются “функции высшего порядка” или “first-class-functions”) позволяют достаточно просто выполнять различные манипуляции с данными, для чего в “обычном” процедурном стиле приходится писать немного больше кода. Все ниженаписанное относится к так называемому функциональному программированию, луркайте подробности.Простая задача есть список
a = [1, 2]
и списокb = [3, 4]
одинаковой длины и нужно слить их парами. Проще простого - используя функциюzip
:a = [1,2] b = [3,4] print zip(a,b) [(1, 3), (2, 4)]
или тройками :
a = [1,2] b = [3,4] c = [5,6] print zip(a,b,c) [(1, 3, 5), (2, 4, 6)]
или в более общем виде
list = [a, b, c] print zip(*list) [(1, 3, 5), (2, 4, 6)]
Далее, функция –
map
. Случаются ситуации, когда внезапно нужно применить какую-либо функцию к каждому элементу списка. Нуб напишет так :def f(x): return x*x nums = [1, 2, 3] for num in nums: print f(num)
Более опытный нуб изучивший
list comprehensions
:def f(x): return x*x print [f(num) for num in nums] Программист сделает проще : def f(x): return x*x print map(f, nums)
А тру-мэдскиллз хакер сделает следующим образом (при условии конечно, что функцию можно записать лямбдой, далеко не всегда функция будет достаточно простой чтобы записать ее лямбдой) :
print map(lambda x: x*x, nums)
Из примера понятно, что map применяет какую-либо функцию к списку и возвращает результат опять же в виде списка. Вы можете передать несколько списков, тогда функция (идущая первым параметром) должна принимать несколько аргументов (по количеству списков переданных в map).
def f(x, y): return x*y a = [1,3,4] b = [3,4,5] print map(f, a, b) [3, 12, 20]
Классно, правда?
Однако если списки разной длины, т.е. Один короче другого, то он будет дополнен значениями None до нужной длины. Если убрать из списка
b
последнее значение – пример не будет работать, т.к. В функцииf
произойдет попытка умножения числа наNone
, и питоне не позволяет это делать. Поэтому если функцияf
достаточно объемна, неплохо бы проверять передаваемые значения. Например;def f(x, y): if (y == None): y = 1 return x*y
Если же заместо функции стоит
None
– то map действует примерно так же как и zip, но если передаваемые списки разной длины в результат будет писаться None – что кстати очень уместно в некоторых моментах.a = [1,3,4] b = [3,4] print map(None, a, b) [(1, 3), (3, 4), (4, None)]
Теперь про лямбда функции в python. Они используются когда вам необходимо определить функцию без исподьзования
def func_name(): ...
, ведь часто (как в предыдущих примерах) функция настолько мала, что определять её отдельно смыла нет (лишние строчки кода, что ухудшение читабельность). Поэтому функцию можно определить “на месте”f = lambda x: x*x
как бы говорит нам – принимаетx
, возвращаетx*x
Так используя стандартные инструменты питона можно записать довольно сложные действия в одну строчку. К примеру функцию :
def f(x, y): if (y == None): y = 1 return x*y
можно представить как :
lambda x, y: x * (y if y is not None else 1)
А теперь хорошо бы передавать списки отсортированные по длине –
len(a) > (b)
– проще простого - воспользуемся функциейsorted
:sorted([a, b], key=lambda x: len(x), reverse=True)
фунция
sorted
принимает список значений([a,b] = [[1,2],[2,4,5]])
и сортирует по ключу key – который у нас задан функциейlen(x)
- возвращающей длину списка, сортируем в порядке убывания(reverse=True)
В конечном итоге вся операция записывается таким образом:
map(lambda x, y: x * (y if y is not None else 1), *sorted([a, b], key=lambda x: len(x), reverse=True))
списки
a
иb
могут быть разной длины и передаваться в каком угодно порядке. Лямбда-выражения удобны для определения не очень сложных функций, которые передаются затем другим функциям. -
Список - это обьект или запись которая имеет ссылку на адрес следующего и предыдущего элемента и поле для хранения значения.
Кортеж, по сути - неизменяемый список. Зачем нужны кортежи, если есть списки?
-
Защита от дурака. То есть кортеж защищен от изменений, как намеренных (что плохо), так и случайных (что хорошо).
-
Меньший размер.
-
Возможность использовать кортежи в качестве ключей словаря.
-
- Все операции над списками, не изменяющие список (сложение, умножение на число, методы
index()
иcount()
и некоторые другие операции). Можно также по-разному менять элементы местами и так далее. -
Mutable — это обекты, значения которых могут быть изменены(например,
list
), а immutable — это обекты, значения которых не может меняться (например,string
). Но это не значит, что если у нас есть переменная immutable типа, то ее нельзя изменить. Например, с типом string все привыкли работать так:In [11]: text = 'Hello' In [12]: text Out[12]: 'Hello' In [13]: text = 'Hello, World' In [14]: text Out[14]: 'Hello, World'
Как мы видим, начение переменной
text
поменялось. На самом деле, при присвоении переменнойtext
нового значения, в памяти создается новый объект, и переменная text начинает на него ссылаться. В этом легко убедится при помощи функцииid()
- получить идентификатор до и после изменения переменной. Mutable типы ведут себя так:In [15]: l = [1, 2, 3] In [16]: l Out[16]: [1, 2, 3] In [17]: id(l) Out[17]: 139901299808088 In [18]: l.append(4) In [19]: l Out[19]: [1, 2, 3, 4] In [20]: id(l) Out[20]: 139901299808088
Основываясь на этом свойстве(и не только), ключами в словаре (dict) могут быть только immutable обекты:
In [21]: d = {'one': 1} In [22]: type(d) Out[22]: dict In [23]: d[1]=1 In [24]: d Out[24]: {1: 1, 'one': 1} In [25]: d[l] = 'list' --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-25-4f49b18d7af7> in <module>() ----> 1 d[l] = 'list' TypeError: unhashable type: 'list'
Immutable типы в Python — это числа(
numbers
), строки (strings
) и кортежи (tuples
). -
Словарь в Python реализован в виде хэш-таблицы. Ключами словаря могут быть значения только hashable типов, то есть типов, у которых может быть получен хэш (для этого у них должен быть метод
__hash__()
). Поэтому значения таких типов, как список (list
), набор (set
) и собственно сам словарь (dict
), не могут быть ключами словаря.Чтобы класс был ключем к нему нужно добавить метод
__hash__()
Подробнее про словари можно почитать здесь
-
@classmethod
means: when this method is called, we pass the class as the first argument instead of the instance of that class (as we normally do with methods). This means you can use the class and its properties inside that method rather than a particular instance.@staticmethod
means: when this method is called, we don’t pass an instance of the class to it (as we normally do with methods). This means you can put a function inside a class but you can’t access the instance of that class (this is useful when your method does not use the instance). -
A metaclass is the class of a class. Like a class defines how an instance of the class behaves, a metaclass defines how a class behaves. A class is an instance of a metaclass.
While in Python you can use arbitrary callables for metaclasses (like Jerub shows), the more useful approach is actually to make it an actual class itself. ‘type’ is the usual metaclass in Python. In case you’re wondering, yes, ‘type’ is itself a class, and it is its own type. You won’t be able to recreate something like ‘type’ purely in Python, but Python cheats a little. To create your own metaclass in Python you really just want to subclass ‘type’.
A metaclass is most commonly used as a class-factory. Like you create an instance of the class by calling the class, Python creates a new class (when it executes the ‘class’ statement) by calling the metaclass. Combined with the normal init and new methods, metaclasses therefore allow you to do ‘extra things’ when creating a class, like registering the new class with some registry, or even replace the class with something else entirely.
When the ‘class’ statement is executed, Python first executes the body of the ‘class’ statement as a normal block of code. The resulting namespace (a dict) holds the attributes of the class-to-be. The metaclass is determined by looking at the baseclasses of the class-to-be (metaclasses are inherited), at the metaclass attribute of the class-to-be (if any) or the ‘metaclass’ global variable. The metaclass is then called with the name, bases and attributes of the class to instantiate it.
However, metaclasses actually define the type of a class, not just a factory for it, so you can do much more with them. You can, for instance, define normal methods on the metaclass. These metaclass-methods are like classmethods, in that they can be called on the class without an instance, but they are also not like classmethods in that they cannot be called on an instance of the class. type.subclasses() is an example of a method on the ‘type’ metaclass. You can also define the normal ‘magic’ methods, like add, iter and getattr, to implement or change how the class behaves.
Here’s an aggregated example of the bits and pieces:
def make_hook(f): """Decorator to turn 'foo' method into '__foo__'""" f.is_hook = 1 return f class MyType(type): def __new__(cls, name, bases, attrs): if name.startswith('None'): return None # Go over attributes and see if they should be renamed. newattrs = {} for attrname, attrvalue in attrs.iteritems(): if getattr(attrvalue, 'is_hook', 0): newattrs['__%s__' % attrname] = attrvalue else: newattrs[attrname] = attrvalue return super(MyType, cls).__new__(cls, name, bases, newattrs) def __init__(self, name, bases, attrs): super(MyType, self).__init__(name, bases, attrs) # classregistry.register(self, self.interfaces) print "Would register class %s now." % self def __add__(self, other): class AutoClass(self, other): pass return AutoClass # Alternatively, to autogenerate the classname as well as the class: # return type(self.__name__ + other.__name__, (self, other), {}) def unregister(self): # classregistry.unregister(self) print "Would unregister class %s now." % self class MyObject: __metaclass__ = MyType class NoneSample(MyObject): pass # Will print "NoneType None" print type(NoneSample), repr(NoneSample) class Example(MyObject): def __init__(self, value): self.value = value @make_hook def add(self, other): return self.__class__(self.value + other.value) # Will unregister the class Example.unregister() inst = Example(10) # Will fail with an AttributeError #inst.unregister() print inst + inst class Sibling(MyObject): pass ExampleSibling = Example + Sibling # ExampleSibling is now a subclass of both Example and Sibling (with no # content of its own) although it will believe it's called 'AutoClass' print ExampleSibling print ExampleSibling.__mro__
-
Очень подробно: http://habrahabr.ru/post/122082/
Если говорить в общем, то дескриптор — это атрибут объекта со связанным поведением (англ. binding behavior), т.е. такой, чьё поведение при доступе переопределяется методами протокола дескриптора. Эти методы:
__get__
,__set__
и__delete__
. Если хотя бы один из этих методов определён для объекта, то он становится дескриптором.Стандартное поведение при доступе к атрибутам — это получение, установка и удаление атрибута из словаря объекта. Например,
a.x
имеет такую цепочку поиска атрибута:a.__dict__['x']
, затем вtype(a).__dict__['x']
, и далее по базовым классамtype(a)
не включая метаклассы. Если же искомое значение — это объект, в котором есть хотя бы один из методов, определяющих дескриптор, то питон может изменить стандартную цепочку поиска и вызвать один из методов дескриптора. Как и когда это произойдёт зависит от того, какие методы дескриптора определены для объекта. Дескрипторы вызываются только для объектов или классов нового стиля (класс является таким, если наследует от object или type).Дескрипторы — это мощный протокол с широкой областью применения. Они являются тем механизмом, который стоит за свойствами, методами, статическими методами, методами класса и вызовом
super()
. Внутри самого питона с их помощью реализуются классы нового стиля, которые были представлены в версии 2.2. Дескрипторы упрощают понимание нижележащего кода на C, а также представляют гибкий набор новых инструментов для любых программ на питоне.###Протокол дескрипторов
descr.__get__(self, obj, type=None) --> значение descr.__set__(self, obj, value) --> None descr.__delete__(self, obj) --> None
Собственно это всё. Определите любой из этих методов и объект будет считаться дескриптором, и сможет переопределять стандартное поведение, если его будут искать как атрибут.
Если объект определяет сразу и
__get__
, и__set__
, то он считается дескриптором данных (англ. data descriptor). Дескрипторы, которые определили только__get__
называются дескрипторами не данных (англ. non-data descriptors). Их называются так, потому что они используют для методов, но другие способы их применения также возможны.Дескрипторы данных и не данных отличаются в том, как будет изменено поведение поиска, если в словаре объекта уже есть запись с таким же именем как у дескриптора. Если попадается дескриптор данных, то он вызывается раньше, чем запись из словаря объекта. Если в такой же ситуации окажется дескриптор не данных, то запись из словаря объекта имеет преимущество перед этим дескриптором.
Чтобы создать дескриптор данных только для чтения, определите и
__get__
, и__set__
, и сделайте так, чтобы set выбрасывал исключениеAttributeError
. Определения метода__set__
и выбрасывания исключения достаточно, чтобы этот дескриптор считался дескриптором данных.###Вызов дескрипторов
Дескриптор можно вызвать напрямую через его метод. Например,
d.__get__(obj)
.Однако, наиболее частый вариант вызова дескриптора — это автоматический вызов во время доступа к атрибуту. Например,
obj.d
ищетd
в словареobj
. Если d определяет метод__get__
, то будет вызванd.__get__(obj)
. Вызов будет сделан согласно правилам, описанным ниже.Детали вызова различаются от того, чем является obj — объектом или классом. В любом случае, дескрипторы работают только для объектов и классов нового стиля. Класс является классом нового стиля, если он является потомком object.
Для объектов алгоритм реализуется с помощью
object.__getattribute__
, который преобразует записьb.x
вtype(b).__dict__['x'].__get__(b, type(b))
. Реализация работает через цепочку предшественников, в которой дескрипторы данных имеют приоритет перед переменными объекта, переменные объекта имеют приоритет перед дескрипторами не данных, и самый низкий приоритет у метода__getattr__
, если он определён. Полную реализацию на языке C можно найти в PyObject_GenericGetAttr() в файле Objects/object.c.Для классов алгоритм реализуется с помощью
type.__getattribute__
, который преобразует записьB.x
вB.__dict__['x'].__get__(None, B)
. На чистом питоне это выглядит так:def __getattribute__(self, key): "Эмуляция type_getattro() в Objects/typeobject.c" v = object.__getattribute__(self, key) if hasattr(v, '__get__'): return v.__get__(None, self) return v
Важные части, которые следует запомнить:
- дескрипторы вызываются с помощью метода
__getattribute__
- переопределение
__getattribute__
прекратит автоматический вызов дескрипторов__getattribute__
доступен только внутри классов и объектов нового стиля object.__getattribute__
иtype.__getattribute__
делают разные вызовы к__get__
- дескрипторы данных всегда имеют преимущество перед переменными объекта
- дескрипторы не данных могут потерять преимущество из-за переменных объекта
Объект, который возвращается после вызова
super()
также имеет собственную реализацию метода__getattribute__
, с помощью которой вызывает дескрипторы. Вызовsuper(B, obj).m()
ищет вobj.__class__.__mro__
базовый классA
, за которым сразу следуетB
, и возвращаетA.__dict__['m'].__get__(obj, A)
. Если это не дескриптор, тоm
возвращается неизменённой. Если m нет в словаре, то возвращаемся к поиску черезobject.__getattribute__
.Примечание: в питоне 2.2,
super(B, obj).m()
вызывал__get__
только если m был дескриптором данных. В питоне 2.3, дескрипторы не данных тоже вызываются, за исключением тех случаев, когда используются классы старого стиля. Детали реализации можно найти в super_getattro() в файле Objects/typeobject.c, а эквивалент на чистом питоне можно найти в пособии от Guido.Детали выше описывают, что алгоритм вызова дескрипторов реализуется с помощью метода
__getattribute__()
для object, type и super. Классы наследуют этот алгоритм, когда они наследуют от object или если у них есть метакласс, реализующий подобную функциональность. Таким образом, классы могут отключить вызов дескрипторов, если переопределят__getattribute__()
.###Пример дескриптора
Следующий код создаёт класс, чьи объекты являются дескрипторам данных и всё, что они делают — это печатают сообщение на каждый вызов
get
илиset
. Переопределение__getattribute__
— это альтернативный подход, с помощью которого мы могли бы сделать это для каждого атрибута. Но если мы хотим наблюдать только за отдельными атрибутами, то это проще сделать с помощью дескриптора.class RevealAccess(object): """Дескриптор данных, который устанавливает и возвращает значения, и печатает сообщение о том, что к атрибуту был доступ. """ def __init__(self, initval=None, name='var'): self.val = initval self.name = name def __get__(self, obj, objtype): print 'Получаю', self.name return self.val def __set__(self, obj, val): print 'Обновляю' , self.name self.val = val >>> class MyClass(object): x = RevealAccess(10, 'var "x"') y = 5 >>> m = MyClass() >>> m.x Получаю var "x" 10 >>> m.x = 20 Обновляю var "x" >>> m.x Получаю var "x" 20 >>> m.y 5
Этот простой протокол предоставляет просто увлекательные возможности. Некоторые из них настолько часто используются, что были объединены в отдельные функции. Свойства, связанные и несвязанные методы, статические методы и методы класса — все они основаны на этом протоколе.
- дескрипторы вызываются с помощью метода
- MTV (Model-Template-View)
Наиболее распространенные виды MVC-паттерна, это:- Model-View-Controller
- Model-View-Presenter
- Model-View-View Model
- После нажатия на ссылку, отправляеться
http
запрос, на указанный адресс. Веб сервер в этот момент ловит все запросы приходящие на указанный порт(по умолчанию 80) и обрабатывает его. Можно указать ряд инстукций что бы вебсервер сразу же отдавал ответ(как например со статикой и медиа файлами) или же мы дёргаем uwsgi файл, который передаёт запрос django по протоколу WSGI, который в свою очередь превращаетhttp
запрос в обьектrequest
и после прохождения middleware слоя попадает в view. View выполняет некую логику и возвращает ответ пользователю. - Middleware - промежуточный слой который может срабатывать перед view и после view
-
pre_save
post_save
post_delete
pre_delete
m2m_changed
request_started
- Sent when Django begins processing an HTTP request.request_finished
- Sent when Django finishes delivering an HTTP response to the client.
- mod_wsgi - модуль для веб-сервера Apache, который предоставляет WSGI-совместимый интерфейс для работы с web-приложениями.
- Работать с “пустой” базой данных неудобно. Поэтому, при настройке и отладке приложения часто возникает необходимость в “начальных” данных для проекта. Django предлагает нам ряд возможностей для автоматического создания таких данных: с помощью файлов предварительной настройки (
fixtures
), либо с помощьюSQL
запросов. -
PK
- первичный ключFK
- внешний ключПервичный ключ (
primary key
) представляет собой один из примеров уникальных индексов и применяется для уникальной идентификации записей таблицы. Никакие из двух записей таблицы не могут иметь одинаковых значений первичного ключа.FK
нужны для поддержания целостности базы, что бы нельзя было создать пост не привязанный ни какому топику, нельзя было удалить топик, если в нем есть посты, или удалить топик, а заодно автоматически удалить из базы все посты связанные с ним. -
GROUP BY
- для аггрегации результирующих строк по заданным признакам-атрибутам.HAVING
- для фильтрации результата GROUP BY по заданным логическим условиям. Используется как WHERE, но в другой части SQL-выражения и, соответственно, на другой стадии формирования ответа.Пример:
Скажем есть у нас Интернет-магазин. Чтобы узнать сколько денег нам принес каждый отдельно взятый покупатель в общей сложности за всё время существования магазина, мы делаем запрос с аггрегацией стоимости купленных товаров для конкретного покупателя:
SELECT customer_name, SUM(order_price) FROM orders GROUP BY customer_name;
Когда мы не хотим видеть “малоактивных покупателей” (те кто купил на малую сумму), мы можем отфильтровать аггрегированные данные из прошлого запроса по какой-то суммарной планке. Скажем, показать тех, кто купил у нас товаров в общей сложности на 100 т.р. и больше:
SELECT customer_name, SUM(order_price) FROM orders GROUP BY customer_name HAVING SUM(order_price) >= 100000;
-
Простой
JOIN
- тоже самое чтоINNER JOIN
и означает показывать только общие записи обоих таблиц. Каким образом записи считаются общими определяется полями в join-выражении. Например следующая записьFROM t1 JOIN t2 on t1.id = t2.id
означает что будут показаны записи с одинаковыми
id
, существующие в обоих таблицах.LEFT JOIN
(или LEFTOUTER JOIN
) означает показывать все записи из левой таблицы (той, которая идет первой в join-выражении) независимо от наличия соответствующих записей в правой таблице.RIGHT JOIN
(илиRIGHT OUTER JOIN
) действует в противоположностьLEFT JOIN
- показывает все записи из правой (второй) таблицы и только совпавшие из левой (первой) таблицы. -
Агрегация это все функции типа
SUM()
,COUNT()
SELECT ProductName, COUNT(product_id) FROM Products
-
for i in x: for j in y: i*j
Сложность алгоритма - зависит от скорости его роста. Вычисляется в количестве элементарных операций или шагов, которые необходимо выполнить. Сложность алгоритма данного в примере можно оценить как
O(n^2)
; -
- Сортировка вставками
- Сортировка выбором
- Сортировка слиянием
- Пузырьковая сортировка
- Пошаговый перебор элементов дерева по связям между узлами-предками и узлами-потомками называется обходом дерева. Зачастую, операция может быть выполнена переходом указателя по отдельным узлам. Обход, при котором каждый узел-предок просматривается прежде его потомков называется предупорядоченным обходом или обходом в прямом порядке (pre-order walk), а когда просматриваются сначала потомки, а потом предки, то обход называется поступорядоченным обходом или обходом в обратном порядке (post-order walk). Существует также симметричный обход, при котором посещается сначала левое поддерево, затем узел, затем — правое поддерево, и обход в ширину, при котором узлы посещаются уровень за уровнем (N-й уровень дерева — множество узлов с высотой N). Каждый уровень обходится слева направо.
-
В Git’е есть два способа включить изменения из одной ветки в другую: merge (слияние) и rebase (перемещение). Merge - эта команда выполняет слияние между последними снимками состояний веток и последним общим предком этих веток, создавая новый снимок состояния (и коммит).
При помощи команды rebase вы можете взять все изменения, которые попали в коммиты на одной из веток, и повторить их на другой.
-
Существует 3 режима команды git reset: –soft, –mixed(по умолчанию), –hard
-
git reset –soft
Возьмем для примера ветку: - A - B - C (master) HEAD указывает на C и индекс совпадает с C.
После выполнения
git reset --soft B
HEAD будет указывать на B и изменения из коммита C будут в индексе, как будто вы их добавили командой
git add
. Если вы сейчас выполнитеgit commit
вы получите коммит полностью идентичный C. -
git reset –mixed (по умолчанию)
Режим –mixed используется по умолчанию, т.е.
git reset --mixed = git reset
Вернемся к тем же начальным условиям: - A - B - C (master)
Выполнив
git reset --mixed B
или
git reset B
HEAD опять же будет указывать на B, но на этот раз изменения из С не будут в индексе и если вы запустите здесь
git commit
ничего не произойдет т.к. ничего нет в индексе. У нас есть все изменения из С, но если запуститьgit status
то вы увидите, что все измененияnot staged
. Чтобы их закоммитить нужно сначала добавить их в индекс командойgit add
и только после этогоgit commit
. -
git reset –hard
Те же самые начальные условия: - A - B - C (master)
Последний режим –hard также как и –mixed переместит HEAD на В и очистит индекс, но в отличие от –mixed жесткий reset изменит файлы в вашей рабочей директории. Если выполнить
git reset --hard B
то изменения из С, равно как и незакоммиченные изменения, будут удалены и файлы в репозитории будут совпадать с B. Учитывая то, что этот режим подразумевает потерю изменений, вы всегда должны проверять
git status
перед тем как выполнить жесткий reset чтобы убедиться что нет незакоммиченных изменений(или они не нужны).
-
Python
Как получить список всех атрибутов объекта
#Как получить список всех публичных атрибутов объекта
Вкакой «магической» переменной хранится содержимое help?
Почему если в цикле меняется список, то используется for x in lst[:]
, что означает [:]
?
#Какие структуры данных в питоне вы знаете и применяли на практике?
#Уровни модели OSI
Протокол tcp/ip
#Что такое юникод
Что выведет данный код на python 2. Какой результат будет на Python 3 (если конечно превратить синтаксис в Python 3)?
What will be the output of the code below? Explain your answer. How would you modify the definition of extendList to produce the presumably desired behavior?
#What will be the output of the code below? Explain your answer.
#Чему равна a = ?
#Что такое процессы и потоки в Python? Какие возникают проблемы?
#Что такое GIL(более подробно)?:
#Что такое итераторы?
#Что такое генераторы?
#Что такое list comprehensions?
Что значит ключевое слово global?
Какие особенности областей видимости в Python?
Функции map, zip, sorted и lambda. Что делают? Быстрее ли работают ?
#Чем отличается list от tuple?
#Операции с кортежами
#Что такое immutable объекты? Какие Вы знаете? В чем особенность?
#Что такое dict? Что может являться ключом? Что не может являться ключом? Каким образом нужно изменить класс что бы он смог быть ключом?
Что такое новые классы? чем отличаются от старых классов?
#Чем отличается @staticmethod от @classmethod?
Что происходит при обращении к property b экземпляра класса А? Как ищутся properties/methods класса?
Что происходит если property не найдено?
Что такое metaclass?
Что такое дескрипторы?
Django
Какой основной шаблон проектирования лежит в основе фреймверка?
#Что пошагово происходит когда пользователь нажал на ссылку? от браузера до приложения и обратно.
Что такое middleware?
#Какие встроенные сигналы бывают в Django?
#Что такое mod_wsgi?
#Что такое fixtures?
##SQL
#Что такое внешний ключ и зачем он нужен?
#Что такое GROUP BY? Что обозначает ключевое слово HAVING?
#Что в чем отличие между LEFT JOIN, RIGHT JOIN и INNER JOIN?
#Релизовать aggregation без orm.
##Алгоритмы
#Что такое сложность алгоритмов? Как вычисляется? Какова сложность алгоритма:
Какие алгоритмы сортировки знаете?
Какие есть способы обхода дерева?
SCM
#Чем git rebase отличается от git merge?
#Что такое git reset?