категории | RSS

Вопросы и задания по Python, а также ответы и решения к ним.
Здесь представлена первая часть ответов. Отсутствуют ответы на пункты "Классы" и "Метаклассы и дескрипторы".
Поэтому продолжение следует...
-----
Ниже следует список вопросов, с помощью которых любой питонщик может проверить свои знания Python, базовые и не очень. Особенно ему помогут в этом ответы fellow.
-----
Вопросы и задания были взяты отсюда: Вопросы и задания по 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)


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,
        []
    )
    )


7. Почему если в цикле меняется список, то используется for x in lst[:] , что означает [:] ?

У операции взятия среза от последовательности [:] много тонкостей, описывать их долго, а желания нет smile, поэтому коротко: изменение в цикле списка, по которому идёт итерация, создаёт благодатную почву для проявления всевозможных сайд-эффектов.
То бишь скорее всего ваш код будет в лучшем случае давать неожиданный результат.
Для того чтобы иметь возможность обрабатывать в цикле элементы списка согласно их расположению и создается копия этого списка.
P.S.: если структура списка и структура его элементов (если это последовательности) в цикле не меняется, можете рискнуть и использовать для итерации исходный список. Это зависит от вашего мастерства: если вы способны предусмотреть все возможные баги, то... на кой чёрт тогда вы читаете мои наставления? fellow
8. Есть два списка одинаковой длины, в одном ключи, в другом значения. Составить словарь.

keys = [1, 3, 5]
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


b.:
keys = [1, 3, 5]
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

11. Есть строка в юникоде, получить 8-битную строку в кодировке utf-8 и utf8

unicodestring = u'unicode string'
utf8string = unicodestring.encode('utf-8')
utf8string = unicodestring.encode('utf8')


12. Есть строка в кодировке utf8, получить юникодную строку

utf8string = 'строка'
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


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))))


# Ох и долго я маялся с этой функцией fellow, всё что-то ускользало от понимания. А вот сел писать "набело" и -- вуаля.

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

Написать варианты с обычной “внутренней” и анонимной lambda-функцией.

def addition(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_))

# полезный совет, полученный на собственном горьком опыте smile:
# если пишете большую 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


4. Написать аналог map:

*. первым аргументом идет либо функция, либо список функций
*. вторым аргументом — список аргументов, которые будут переданы функциям
*. полагается, что эти функции — функции одного аргумента
>>> mymap([add0, add1, add2], [1, 2, 3])
[(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)


# Я немного схитрил: мой вариант 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


Для функций и итераторов написать доктесты

from __future__ import generators
def chain(*iterators):
    for iterator in iterators:
        for obj in iterator:
            yield obj


Никаких доктестов от меня вы не дождетесь winked, ибо смутно я догадываюсь что это проверка на то, не могут ли написанные функции и итераторы "поломаться", если в них передать не то или использовать их каким-нибудь идиотским способом. Для этого пришлось бы, например, проверять аргументы на корректность и т.д., потому что вышеприведенные функции "наивны": предполагается, что на вход всегда подаются корректные аргументы.
==========
Модули
|

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

4. У вас есть модуль foo, внутри него импортируется модуль bar. Рядом с модулем foo есть файлы bar.py и bar/__init__.py Какой модуль будет использоваться.

bar/__init__.py

Проверено эмпирически. То есть опытным путём fellow.
Какой тезис Дзен Python лёг в основу этого чуда, я не знаю.
5. Что означает и для чего используется конструкция __name__ == '__main__'

Это такая банальная штука, что отвечать на неё попросту скучно.

Virtuos86
2010-06-01T12:09:31Z

Здесь находятся
всего 0. За сутки здесь было 0 человек

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

#2   Virtuos86    

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


0 ответить

#2   dimy44    

Высший пилотаж). Надеюсь, продолжение следует... Не так сказал. Надеюсь долго ждать не придется. Не терпится еще интересного подчерпнуть.


* редактировал(а) dimy44 14:52 1 июн 2010

0 ответить