Skip to content

Instantly share code, notes, and snippets.

@malinoff
Created May 21, 2012 04:44
Show Gist options
  • Save malinoff/2760585 to your computer and use it in GitHub Desktop.
Save malinoff/2760585 to your computer and use it in GitHub Desktop.
HiDevLab answers
#Типы данных, основные конструкции
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