Created
May 21, 2012 04:44
-
-
Save malinoff/2760585 to your computer and use it in GitHub Desktop.
HiDevLab answers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Типы данных, основные конструкции | |
Q: Как получить список всех атрибутов объекта | |
A: dir(obj) | |
Q: Как получить список всех публичных атрибутов объекта | |
A: [x for x in dir(obj) if x[0] != '_'] | |
Q: Как получить список методов объекта | |
A: [x for x in dir(obj) if callable(getattr(obj,x)] | |
Q: В какой "магической" переменной хранится содержимое help? | |
A: obj.__doc__ | |
Q: Есть два кортежа, получить третий как конкатенацию первых двух | |
A: t1 = (1,2) | |
t2 = (5,6) | |
t3 = t1 + t2 | |
Q: Есть два кортежа, получить третий как объединение уникальных элементов первых двух кортежей | |
A: t1 = (1,2,3) | |
t2 = (3,4,5) | |
t = tuple(reduce( | |
lambda list, elem: (elem not in list) and list.append(elem) or list, | |
c1 + c2, | |
[])) | |
Q: Почему если в цикле меняется список, то используется for x in lst[:], что означает [:]? | |
A: [:] - означает взятие среза с первого по последний элементы списка, | |
используется для создании копии списка, чтобы не изменялся исходный список | |
Q: Есть два списка одинаковой длины, в одном ключи, в другом значения. Составить словарь. | |
A: l1 = ['a','b','c'] | |
l2 = [1,2,3] | |
d = dict(zip(l1,l2)) | |
Q: Есть два списка разной длины, в одном ключи, в другом значения. Составить словарь. | |
Для ключей, для которых нет значений использовать None в качестве значения. | |
Значения, для которых нет ключей игнорировать. | |
A: keys = ['a','b','c'] | |
values = [1,2] | |
d = dict(map(None, keys, values)) #Случай, когда len(keys) > len(values) | |
# keys - неизменен | |
values = [1,2,3,4] | |
d = dict(zip(keys, [values[x] for x in range(len(keys))])) | |
Q: Есть словарь. Инвертировать его. Т.е. пары ключ: значение поменять местами значение: ключ. | |
A: d = {'a' : 1, 'b' : 2} | |
d = dict(zip(d.values(), d.keys())) | |
Q: Есть строка в юникоде, получить 8-битную строку в кодировке utf-8 и cp1251 | |
A: s_unicode = u'unicode string' | |
s_utf = s_unicode.encode('utf-8') | |
s_cp1251 = s_unicode.encode('cp1251') | |
Q: Есть строка в кодировке cp1251, получить юникодную строку | |
A: ustr = s_cp1251.decode('cp1251') | |
# Функции | |
Q: Написать функцию, которой можно передавать аргументы либо списком/кортежем, либо по одному. | |
Функция производит суммирование всех аргументов. | |
A: | |
def f(*args): | |
""" | |
>>> f(1, 2, 3) | |
6 | |
>>> f([1, 2, 3]) | |
6 | |
>>> f((3, 5, 6)) | |
14 | |
>>> f(3, (5, 6)) | |
14 | |
""" | |
sum = 0 | |
for arg in args: | |
if hasattr(arg, '__len__'): | |
sum += f(*arg) | |
else: | |
sum += arg | |
return sum | |
Q: Написать функцию-фабрику, которая будет возвращать функцию сложения с аргументом. | |
A: | |
def simple_addition(first_arg): | |
""" | |
>>> add5 = simple_addition(5) | |
>>> add5(3) | |
8 | |
>>> add5(8) | |
13 | |
>>> add8 = simple_addition(8) | |
>>> add8(2) | |
10 | |
>>> add8(4) | |
12 | |
""" | |
def inner(second_arg): | |
return first_arg + second_arg | |
return inner | |
#Написать варианты с обычной "внутренней" и анонимной lambda-функцией. | |
def lambda_addition(first_arg): | |
""" | |
>>> add5 = lambda_addition(5) | |
>>> add5(3) | |
8 | |
>>> add5(8) | |
13 | |
>>> add8 = lambda_addition(8) | |
>>> add8(2) | |
10 | |
>>> add8(4) | |
12 | |
""" | |
return lambda second_arg: first_arg + second_arg | |
Q: Написать фабрику, аналогичную п.2, но возвращающей список таких функций | |
A: | |
def addition_range(low, hi): | |
""" | |
>>> addit = addition_range(0,5) | |
>>> for x in addit: | |
... print x(2) | |
... | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
""" | |
return [lambda arg, x=x: arg + x for x in xrange(low,hi + 1)] | |
Q:Написать аналог map: | |
первым аргументом идет либо функция, либо список функций | |
вторым аргументом — список аргументов, которые будут переданы функциям | |
полагается, что эти функции — функции одного аргумента | |
A: | |
def mymap(funcs, args): | |
""" | |
>>> mymap(lambda x: x*x, (1,2,3)) | |
[1, 4, 9] | |
>>> mymap(x*x, (1,2,3)) | |
Traceback (most recent call last): | |
... | |
NameError: name 'x' is not defined | |
>>> mymap(lambda x: x*x, 1,2,3) | |
Traceback (most recent call last): | |
... | |
TypeError: mymap() takes exactly 2 arguments (4 given) | |
>>> mymap([lambda x: x + x, lambda x: x * x], [1, 2, 3]) | |
[(2, 4, 6), (1, 4, 9)] | |
""" | |
if hasattr(funcs, '__len__'): | |
return [tuple([func(arg) for arg in args]) for func in funcs] | |
else: | |
return map(funcs, args) | |
#Итераторы | |
Q: Написать функцию-генератор cycle которая бы возвращала циклический итератор. | |
A: | |
def cycle(iterator): | |
""" | |
>>> i = iter([1, 2, 3]) | |
>>> c = cycle(i) | |
>>> c.next() | |
1 | |
>>> c.next() | |
2 | |
>>> c.next() | |
3 | |
>>> c.next() | |
1 | |
""" | |
while True: | |
for obj in iterator: | |
yield obj | |
Q: Написать функцию-генератор chain, которая последовательно итерирует переданные | |
объекты (произвольное количество) | |
A: | |
def chain(*iterators): | |
""" | |
>>> 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 | |
""" | |
for iterator in iterators: | |
for obj in iterator: | |
yield obj | |
Q: Для функций и итераторов написать доктесты | |
A: | |
if __name__ == '__main__': | |
import doctest | |
doctest.testmod() | |
#Модули | |
Q: У нас есть импортированный модуль foo, как узнать физический путь файла, | |
откуда он импортирован? | |
A: foo.__file__ | |
Q: Из модуля foo вы импортируете модуль feedparser. Версия X feedparser'а | |
есть в общесистемном каталоге site-packages, версия Y — рядом с модулем | |
foo. Определена переменная окружения PYTHONPATH, и там тоже есть feedparser, | |
версии Z. Какая версия будет использоваться? | |
A: Поиск будет производиться, в первую очередь, в текущем каталоге, то есть, | |
в каталоге, в котором находится модуль foo. Поэтому будет использоваться версия Y | |
Q: Как посмотреть список каталогов, в которых Python ищет модули? | |
A: import sys | |
sys.path | |
Q: У вас есть модуль foo, внутри него импортируется модуль bar. Рядом с модулем foo | |
есть файлы bar.py и bar/__init__.py. Какой модуль будет использоваться? | |
A: Будет использоваться файл bar/__init__.py | |
Q: Что означает и для чего используется конструкция __name__ == '__main__' | |
A: Конструкция используется для того, чтобы узнать, каким образом используется модуль. | |
Если истина - то модуль используется, как основной модуль, если ложь - то модуль | |
подключен инструкцией import в другом модуле. | |
#Классы | |
Q: Написать базовый класс Observable, который бы позволял наследникам: | |
при передаче **kwargs заносить соответствующие значения как атрибуты | |
сделать так, чтобы при print отображались все публичные атрибуты | |
A: | |
class Observable: | |
def __init__(self, **kwargs): | |
for arg in kwargs: | |
setattr(self, arg, kwargs[arg]) | |
def __repr__(self): | |
string = self.__class__.__name__ | |
string += '(' | |
string += ', '.join(x + '=' + str(getattr(self, x)) for x in self.__dict__ | |
if not x.startswith('__')) | |
string += ')' | |
return string | |
Q: Написать класс, который бы по всем внешним признакам был бы словарем, но позволял | |
обращаться к ключам как к атрибутам. | |
A: | |
class DictAttr(dict): | |
def __setattr__(self, attrname, attrvalue): | |
self[attrname] = attrvalue | |
def __getattr__(self, attrname): | |
if KeyError: | |
raise AttributeError, attrname | |
else: | |
return self[attrname] | |
Q: Пункт 2 с усложнением: написать родительский класс XDictAttr так, чтобы у наследника | |
динамически определялся ключ по наличию метода get_<KEY>. | |
A: | |
class XDictAttr(DictAttr): | |
def __repr__(self): | |
string = self.__class__.__name__ + ':' + DictAttr.__repr__(self) | |
return string | |
def _isAttr(self, name): | |
attrName = 'get_' + name | |
if hasattr(self.__class__, attrName): | |
funcAttr = getattr(self, attrName) | |
return funcAttr() | |
else: | |
raise KeyError(name) | |
def __getattr__(self, name): | |
try: | |
return self[name] | |
except KeyError: | |
return self._isAttr(name) | |
def __getitem__(self, name): | |
if name in self: | |
return DictAttr.__getitem__(self, name) | |
else: | |
return self._isAttr(name) | |
def get(self, name, msg = None): | |
try: | |
return self[name] | |
except KeyError: | |
return msg | |
Q: Написать класс, который регистрирует свои экземпляры и предоставляет интерфейс | |
итератора по ним | |
A: | |
# Не придумал, как решить проблему с удалением пользователем ссылки на объект | |
# при удалении объект остается в списке | |
class MetaIterator(type): | |
def __iter__(self): | |
return iter(self.lst) | |
class Reg(object): | |
__metaclass__ = MetaIterator | |
lst = [] | |
def __init__(self): | |
self.__class__.lst.append(self) | |
Q: Написать юнит-тесты, за основу брать тесты выше, но не ограничиваясь ими. | |
A: | |
if __name__ == '__main__': | |
import unittest | |
class TestClasses(unittest.TestCase): | |
def testObservable(self): | |
class X(Observable): pass | |
x = X(foo=1, bar=5, _bazz=12, name='Amok', props=('One', 'Two') | |
self.assertEqual(str(x), | |
'X(foo=1, bar=5, _bazz=12, name=Amok, props('One', 'Two'))') | |
self.assertEqual(x.foo, 1) | |
self.assertEqual(x.name, 'Amok') | |
self.assertEqual(x._bazz, 12) | |
def testDictAttr(self): | |
x = DictAttr([('one', 1), ('two', 2), ('three', 3)]) | |
self.assertEqual(x['three'], 3) | |
self.assertEqual(x.get('one'), 1) | |
self.assertEqual(x.get('five', 'missing'), 'missing') | |
self.assertEqual(x.one, 1) | |
self.assertRaises(AttributeError, getattr, x, 'five') | |
def testXDictAttr(self): | |
class X2(XDictAttr): | |
def get_foo(self): | |
return 5 | |
def get_bar(self): | |
return 12 | |
x = X2({'one': 1, 'two': 2, 'three': 3}) | |
self.assertEqual(x['one'], 1) | |
self.assertEqual(x.three, 3) | |
self.assertEqual(x.bar, 12) | |
self.assertEqual(x['foo'], 5) | |
self.assertEqual(x.get('foo', 'missing'), 5) | |
self.assertEqual(x.get('bzz', 'missing'), 'missing') | |
def testReg(self): | |
x = Reg() | |
y = Reg() | |
z = Reg() | |
self.assertTrue([x, y, z], [elem for elem in Reg]) | |
unittest.main() | |
#Метаклассы и дескрипторы | |
#Вопросы: | |
Q: Для чего используются, какие аргументы получают, что должны возвращать: | |
методы __new__ и __init__ классов | |
A: __new__ используется для контроля создания экземпляра, получает | |
self - ссылка на экземпляр, | |
*args - кортеж неименованных аргументов, | |
**kwargs - словарь именованных аргументов, | |
вовзращает экземпляр класса | |
__init__ используется для контроля инициализации уже созданного экземпляра, | |
получает те же аргументы, что и __new__, возвращает None | |
Q: Какие аргументы получает __new__ и __init__ у метакласса? | |
A: __new__ принимает cls - метакласс, name - имя создаваемого класса, | |
bases - кортеж родительских классов, dict - словарь атрибутов | |
__init__ - аналогично __new__, вместо cls - self, класс | |
#Задания | |
Q: Реализовать дескрипторы, которые бы фиксировали тип атрибута | |
A: | |
class Property(object): | |
def __init__(self, value = None): | |
self.__dict__['data'] = value | |
def __get__(self, obj, objType = None): | |
return self.__dict__['data'] | |
def __set__(self, obj, value): | |
if type(self.__dict__['data']) != type(value): | |
raise TypeError | |
self.__dict__['data'] = value | |
class ImageProp(object): | |
height = Property(0) | |
width = Property(0) | |
path = Property('/tmp/') | |
size = Property(0) | |
Q: Реализовать базовый класс (используя метакласс), который бы фиксировал тип | |
атрибута | |
A: | |
class MyMeta(type): | |
def __new__(cls, name, bases, dict): | |
for elem in dict: | |
if elem[0] != '_': | |
dict[elem] = Property(dict[elem]) | |
return super(MyMeta, cls).__new__(cls, name, bases, dict) | |
class ImageMeta(object): | |
height = 0 | |
width = 0 | |
path = '/tmp' | |
size = 0 | |
__metaclass__ = MyMeta | |
Q: Реализовать базовый класс (используя метакласс) и дескрипторы, | |
которые бы на основе класса создавали SQL-схему (ANSI SQL) для модели: | |
A: | |
# Не понял, как сюда приделать метакласс, и тем более, дескрипторы | |
class Record: | |
pass | |
class Integer(Record): | |
def sql(self): | |
return 'integer' | |
class Str(Record): | |
def __init__(self, limit): | |
self.limit = limit | |
def sql(self): | |
return 'varchar(%d)' % self.limit | |
class Table: | |
@classmethod | |
def sql(cls): | |
attrs = [(key, val) for key, val in cls.__dict__.items() if isinstance(val, Record)] | |
retString = 'CREATE TABLE %s (\n' % cls.__name__ | |
retString += ',\n'.join([' %s %s' % (x, y.sql()) for x,y in attrs]) | |
retString += '\n)' | |
return retString | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment