Вопросы и задания по Python, а также ответы и решения к ним.
Здесь представлена первая часть ответов. Отсутствуют ответы на пункты "Классы" и "Метаклассы и дескрипторы".
Поэтому продолжение следует...
-----
Ниже следует список вопросов, с помощью которых любой питонщик может проверить свои знания Python, базовые и не очень. Особенно ему помогут в этом ответы
.
-----
Вопросы и задания были взяты отсюда: Вопросы и задания по Python
-----
==========
Типы данных, основные конструкции
|
1. Как получить список всех атрибутов объекта
dir(<obj>)
2. Как получить список всех публичных атрибутов объекта
[attr for attr in dir(<obj>) if not attr.startswith('__')]
# Тут вопрос в том, что считать НЕпубличными, то бишь приватными, атрибутами: вообще приватными считаются атрибуты, имена которых начинаются с двух символов подчеркивания и заканчиваются не более чем одним символом подчеркивания.
# Но куда отнести тогда атрибуты с именами, начинающимися с одного символа подчеркивания? Я их отношу всё же к публичным атрибутам, поскольку для их имён не выполняется характерное преобразование имени.
3. Как получить список методов объекта
[attr for attr in dir(<obj>) if callable(getattr(<obj>, attr))]
4. В какой “магической” переменной хранится содержимое help?
<obj>.__doc__
#?: help(<obj>) на смартфоне можно использовать только на 9-ках с установленным PyS60 версии выше 1.9
5. Есть два кортежа, получить третий как конкатенацию первых двух
one = (1, )
two = 2,
three = one + two -> (1, 2)
two = 2,
three = one + two -> (1, 2)
6. Есть два кортежа, получить третий как объединение уникальных элементов первых двух кортежей
one = 1, 2, 3
two = 1, 2
three = tuple(
reduce(
lambda lst, item: (item not in lst) and lst.append(item) or lst,
one+two,
[]
)
)
two = 1, 2
three = tuple(
reduce(
lambda lst, item: (item not in lst) and lst.append(item) or lst,
one+two,
[]
)
)
7. Почему если в цикле меняется список, то используется for x in lst[:] , что означает [:] ?
У операции взятия среза от последовательности [:] много тонкостей, описывать их долго, а желания нет
То бишь скорее всего ваш код будет в лучшем случае давать неожиданный результат.
Для того чтобы иметь возможность обрабатывать в цикле элементы списка согласно их расположению и создается копия этого списка.
P.S.: если структура списка и структура его элементов (если это последовательности) в цикле не меняется, можете рискнуть и использовать для итерации исходный список. Это зависит от вашего мастерства: если вы способны предусмотреть все возможные баги, то... на кой чёрт тогда вы читаете мои наставления?
8. Есть два списка одинаковой длины, в одном ключи, в другом значения. Составить словарь.
keys = [1, 3, 5]
values = [0, 2, 4]
dictionary = dict(zip(keys, values))
# или dict(map(None, keys, values))
print dictionary
values = [0, 2, 4]
dictionary = dict(zip(keys, values))
# или dict(map(None, keys, values))
print dictionary
9. Есть два списка разной длины, в одном ключи, в другом значения. Составить словарь.
a. Для ключей, для которых нет значений испол ьзовать None в качестве значения.
b. Значения, для которых нет ключей игнорировать.
a.:
keys = [1, 3, 5, 7, 9]
values = [0, 2, 4]
dictionary = dict(map(None, keys, values))
print dictionary
values = [0, 2, 4]
dictionary = dict(map(None, keys, values))
print dictionary
b.:
keys = [1, 3, 5]
values = [0, 2, 4, 6, 8]
dictionary = dict(zip(keys, values))
print dictionary
values = [0, 2, 4, 6, 8]
dictionary = dict(zip(keys, values))
print dictionary
10. Есть словарь. Инвертировать его. Т.е. пары ключ: значение поменять местами — значение: ключ.
dictionary = {'key0': 'value0', 'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
temp = dictionary.items()
dictionary.clear()
for key, value in temp:
dictionary[value] = key
print dictionary
temp = dictionary.items()
dictionary.clear()
for key, value in temp:
dictionary[value] = key
print dictionary
11. Есть строка в юникоде, получить 8-битную строку в кодировке utf-8 и utf8
unicodestring = u'unicode string'
utf8string = unicodestring.encode('utf-8')
utf8string = unicodestring.encode('utf8')
utf8string = unicodestring.encode('utf-8')
utf8string = unicodestring.encode('utf8')
12. Есть строка в кодировке utf8, получить юникодную строку
utf8string = 'строка'
unicodestring = unicode(utf8string, 'utf8') # utf8string.decode('utf8')
unicodestring = unicode(utf8string, 'utf8') # utf8string.decode('utf8')
==========
Функции
|
1. Написать функцию, которой можно передавать аргументы либо списком/кортежем, либо по одному. Функция производит суммирование всех аргументов.
>>> f(1, 2, 3)
6
>>> f([1, 2, 3])
6
>>> f((3, 5, 6))
14
>>> f(3, (5, 6))
14
6
>>> f([1, 2, 3])
6
>>> f((3, 5, 6))
14
>>> f(3, (5, 6))
14
def f(*args):
result = 0
for a in args:
# Если аргумент - последовательнось,
if hasattr(a, '__len__'):
# рекурсивно вызываем функцию 'f' до полной обработки аргумента,
result += f(*a)
# иначе прибавляем значение аргумента к результату.
else:
result += a
return result
print f(1, 2, 3)
print f([1, 2, 3])
print f((3, 5, 6))
print f(3, (5, (6, (8, 10))))
result = 0
for a in args:
# Если аргумент - последовательнось,
if hasattr(a, '__len__'):
# рекурсивно вызываем функцию 'f' до полной обработки аргумента,
result += f(*a)
# иначе прибавляем значение аргумента к результату.
else:
result += a
return result
print f(1, 2, 3)
print f([1, 2, 3])
print f((3, 5, 6))
print f(3, (5, (6, (8, 10))))
# Ох и долго я маялся с этой функцией
2. Написать функцию-фабрику, которая будет возвращать функцию сложения с аргументом.
>>> add5 = addition(5) # функция addition возвращает функцию сложения с 5
>>> add5(3) # вернет 3 + 5 = 8
8
>>> add5(8) # вернет 8 + 5 = 13
13
>>> add8 = addition(8)
>>> add8(2) # вернет 2 + 8 = 10
10
>>> add8(4) # вернет 4 + 8 = 12
12
>>> add5(3) # вернет 3 + 5 = 8
8
>>> add5(8) # вернет 8 + 5 = 13
13
>>> add8 = addition(8)
>>> add8(2) # вернет 2 + 8 = 10
10
>>> add8(4) # вернет 4 + 8 = 12
12
Написать варианты с обычной “внутренней” и анонимной lambda-функцией.
def addition(additional):
def inner(integer):
return integer + additional
return inner
addition = lambda additional: lambda integer: integer + additional
def inner(integer):
return integer + additional
return inner
addition = lambda additional: lambda integer: integer + additional
3. Написать фабрику, аналогичную п.2, но возвращающей список таких функций
def addition_range(*range_):
def inner_maker(additional):
def inner(integer):
return integer + additional
return inner
return map(inner_maker, xrange(*range_))
addition_range = lambda *range_: map(lambda additional:
(lambda integer: integer + additional),
xrange(*range_))
def inner_maker(additional):
def inner(integer):
return integer + additional
return inner
return map(inner_maker, xrange(*range_))
addition_range = lambda *range_: map(lambda additional:
(lambda integer: integer + additional),
xrange(*range_))
# полезный совет, полученный на собственном горьком опыте
# если пишете большую lambda, располагайте её на нескольких строках (я надеюсь, вы владеете этим приёмом?),
# чтобы каждое большое выражение лежало на отдельной строке;
# если какое-либо выражение при вычислении будет вызывать исключение,
# интерпретатор сможет точно указать на проблемное место (номер строки).
# Если lambda записана в одну строку, по трейсбэку и типу исключения можно будет понять лишь, что исключение возникло где-то в этой огромной конструкции.
# Постарайтесь следовать этой рекомендации хотя бы на этапе отладки кода, в готовом варианте можете расположить уже отлаженные и проверенные lambda в одну строку.
>>> additionals = addition_range(0, 5) # список из функций сложения от 0 до 5 включительно
т.е. аналогичное [add0, add1, add2, add3, add4, add5]
>>> for f in additionals:
print f(5), # вернет 0 + 5, 1 + 5, 2 + 5, 3 + 5, 4 + 5
print
print f(5), # вернет 0 + 5, 1 + 5, 2 + 5, 3 + 5, 4 + 5
4. Написать аналог map:
*. первым аргументом идет либо функция, либо список функций
*. вторым аргументом — список аргументов, которые будут переданы функциям
*. полагается, что эти функции — функции одного аргумента
>>> mymap([add0, add1, add2], [1, 2, 3])
[(1, 2, 3), (2, 3, 4), (3, 4, 5)]
[(1, 2, 3), (2, 3, 4), (3, 4, 5)]
в данном случае “развернутая” запись будет: [(add0(1), add0(2), add0(3)), (add1(1), add1(2), add1(3)), (add2(1), add2(2), add2(3))]
def mymap(objs, args):
if hasattr(objs, '__len__'):
return [[f(arg) for arg in args] for f in objs]
else:
return map(objs, args)
if hasattr(objs, '__len__'):
return [[f(arg) for arg in args] for f in objs]
else:
return map(objs, args)
# Я немного схитрил: мой вариант mymap возвращает список списков, а требуется список кортежей.
# В PyS60 1.4.x нет генераторных выражений, поэтому я воспользовался списковыми встраиваниями,
# чтобы не засорять алгоритм.
==========
Итераторы
|
1. Написать функцию-генератор cycle которая бы возвращала циклический итератор.
>>> i = iter([1, 2, 3])
>>> c = cycle(i)
>>> c.next()
1
>>> c.next()
2
>>> c.next()
3
>>> c.next()
1
from __future__ import generators
def cycle(iterator):
'''Генератор циклических итераторов.
Получает на вход итератор iterator.
Возвращает циклический итератор.'''
pseudo_iterator = [i for i in iterator] # Здесь должно быть генераторное выражение (i for i in iterator). Увы, в Python 2.2.2, а значит и в PyS60 1.4.5, их нет :(. Если стоит вопрос о прожорливости памяти, нужно переписать генератор немного по-другому, заменив списковое включение на цикл for.
while 1:
for i in pseudo_iterator:
yield i
2. Написать функцию-генератор chain, которая последовательно итерирует переданные объекты (произвольное количество)
>>> i1 = iter([1, 2, 3])
>>> i2 = iter([4, 5])
>>> c = chain(i1, i2)
>>> c.next()
1
>>> c.next()
2
>>> c.next()
3
>>> c.next()
4
>>> c.next()
5
>>> c.next()
Traceback (most recent call last):
...
StopIteration
>>> i2 = iter([4, 5])
>>> c = chain(i1, i2)
>>> c.next()
1
>>> c.next()
2
>>> c.next()
3
>>> c.next()
4
>>> c.next()
5
>>> c.next()
Traceback (most recent call last):
...
StopIteration
Для функций и итераторов написать доктесты
from __future__ import generators
def chain(*iterators):
for iterator in iterators:
for obj in iterator:
yield obj
def chain(*iterators):
for iterator in iterators:
for obj in iterator:
yield obj
Никаких доктестов от меня вы не дождетесь
==========
Модули
|
1. У нас есть импортированный модуль foo, как узнать физический путь файла, откуда он импортирован?
foo.__file__
2. Из модуля foo вы импортируете модуль feedparser. Версия X feedparser'а есть в общесистемном каталоге site-packages, версия Y — рядом с модулем foo. Определена переменная окружения PYTHONPATH , и там тоже есть feedparser, версии Z. Какая версия будет использоваться?
Сначала модуль ищется в текущем каталоге, затем в каталогах, указанных в PYTHONPATH, и в конце концов в зависящих от платформы путях по умолчанию. Следовательно, в данном случае будет импортирован версия Y модуля feedparser.
3. Как посмотреть список каталогов, в которых Python ищет модули?
import sys
print sys.path
print sys.path
4. У вас есть модуль foo, внутри него импортируется модуль bar. Рядом с модулем foo есть файлы bar.py и bar/__init__.py Какой модуль будет использоваться.
bar/__init__.py
Проверено эмпирически. То есть опытным путём
Какой тезис Дзен Python лёг в основу этого чуда, я не знаю.
5. Что означает и для чего используется конструкция __name__ == '__main__'
Это такая банальная штука, что отвечать на неё попросту скучно.


Забавно. Обнаружил в инете две отсылки к этому посту: один в блоге, в котором приведены очень хорошие решения _настоящим_ программистом, а не вшивым энтузиастом, как я
; другой в комментах к статье на хабре, тоже с ответами.
Похоже заметый отрыв просмотров моей публикации связан с этим фактом.
А мне не жалко. Жалко отсутствие фидбэка - обратной связи.
Nobody cares.
0 ответить