Самоучитель PythonВыпуск 2Дмитрий Мусинмая 07, 2017
Скачать 0.74 Mb.
|
Как узнать доступные методы и атрибуты объекта? dir(x) возвращает список методов и атрибутов. Как можно узнать имя объекта? Вообще говоря, никак, поскольку объекты в действительности не имеют имён. Важно: присваивание всегда связывает имя с объектом. Это верно и для инструкций def и class. >>> class A : pass >>> B = A >>> >>> a = B() >>> b = a >>> (b) <__main__.A object at 0x7fbcc3ee5160> >>> (a) <__main__.A object at 0x7fbcc3ee5160> 33.10. Как скопировать объект в Python? 141 Самоучитель Python, Выпуск 0.2 Возможно, класс имеет имя: однако, хотя он связан с двумя именами и запрашивается че- рез имя B, созданный экземпляр всё ещё считается экземпляром класса A. Однако, невоз- можно сказать, имя экземпляра a или b, поскольку оба они связаны с одним и тем же значением. Какой приоритет у оператора “запятая”? Запятая не является оператором в Python. >>> "a" in "b" , "a" (False, 'a') Поскольку запятая - не оператор, но разделитель между выражениями, пример выше ис- полняется как если бы было введено: ( "a" in "b" ), "a" А не "a" in ( "b" , "a" ) То же самое верно и для операторов присваивания (=, += и другие). Они не являются опе- раторами как таковыми, а лишь синтаксическими разделителями в операциях присваи- вания. Есть ли в Python эквивалент тернарного оператора ”?:” в C? Да. Синтаксис: [on_true] if [expression] else [on_false] x, y = 50 , 25 small = x if x < y else y Можно ли писать обфусцированные однострочники? Можно. from functools import reduce # Простые числа < 1000 ( list ( filter ( None , map ( lambda y:y * reduce( lambda x,y:x * y != 0 , map ( lambda x,y = y:y % x, range ( 2 , int ( pow (y, 0.5 ) + 1 ))), 1 ), range ( 2 , 1000 ))))) 33.13. Какой приоритет у оператора “запятая”? 142 Самоучитель Python, Выпуск 0.2 # Первые 10 чисел Фибоначчи print ( list ( map ( lambda x,f = lambda x,f:(f(x - 1 ,f) + f(x - 2 ,f)) if x > 1 else 1 : f(x,f), range ( 10 )))) # Множество Мандельброта print (( lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce( lambda x,y:x + y, map ( lambda y, Iu = Iu,Io = Io,Ru = Ru,Ro = Ro,Sy = Sy,L = lambda yc,Iu = Iu,Io = Io,Ru = Ru,Ro = Ro,i = IM, Sx = Sx,Sy = Sy:reduce( lambda x,y:x + y, map ( lambda x,xc = Ru,yc = yc,Ru = Ru,Ro = Ro, i = i,Sx = Sx,F = lambda xc,yc,x,y,k,f = lambda xc,yc,x,y,k,f:(k <= 0 ) or (x * x + y * y >= 4.0 ) or 1 + f(xc,yc,x * x - y * y + xc, 2.0 * x * y + yc,k - 1 ,f):f(xc,yc,x,y,k,f): chr ( 64 + F(Ru + x * (Ro - Ru) / Sx,yc, 0 , 0 ,i)), range (Sx))):L(Iu + y * (Io - Iu) / Sy), range (Sy ))))( - 2.1 , 0.7 , - 1.2 , 1.2 , 30 , 80 , 24 )) # \___ ___/ \___ ___/ | | |__ lines on screen # V V | |______ columns on screen # | | |__________ maximum of "iterations" # | |_________________ range on y axis # |____________________________ range on x axis Не пытайтесь это делать дома! Почему -22 // 10 равно -3? Поскольку i % j имеет тот же знак, что j. А ещё i == (i // j) * j + (i % j) Как можно изменить строку? Никак, поскольку строки неизменяемы. В большинстве ситуаций, нужно просто сделать новую строку из различных частей. Однако, если так нужно, можно использовать io. StringIO, либо модуль array : >>> import io >>> s = "Hello, world" >>> sio = io StringIO(s) >>> sio getvalue() 'Hello, world' >>> sio seek( 7 ) 7 >>> sio write( "there!" ) 6 >>> sio getvalue() 'Hello, there!' >>> import array 33.16. Почему -22 // 10 равно -3? 143 Самоучитель Python, Выпуск 0.2 >>> a = array array( 'u' , s) >>> (a) array('u', 'Hello, world') >>> a[ 0 ] = 'y' >>> (a) array('u', 'yello, world') >>> a tounicode() 'yello, world' Как использовать строки для вызова функций/методов? Существует несколько приёмов. • Лучший - использование словаря, ставящего соответствие строке функцию. Его глав- ное достоинство - строки не обязаны совпадать с названиями функций. def a (): pass def b (): pass dispatch = { 'go' : a, 'stop' : b} # Note lack of parens for funcs dispatch[get_input()]() • Использование встроенной функции getattr: import foo getattr (foo, 'bar' )() • Использование locals или eval (не рекомендуется) def myFunc (): ( "hello" ) fname = "myFunc" f = locals ()[fname] f() f = eval (fname) f() 33.18. Как использовать строки для вызова функций/методов? 144 Самоучитель Python, Выпуск 0.2 Как удалить все символы новой строки в конце строки? Можно использовать S.rstrip("\r\n") для удаления символов новой строки, без удале- ния конечных пробелов: >>> lines = ( "line 1 \r\n" "\r\n" "\r\n" ) >>> lines rstrip( "\r\n" ) 'line 1 ' Как удалить повторяющиеся элементы в списке? Существует несколько путей: http://code.activestate.com/recipes/52560/ Как создать многомерный список? Возможно, вы попробуете этот неудачный вариант: >>> A = [[ None ] * 2 ] * 3 Это выглядит правильно, если напечатать: >>> A [[None, None], [None, None], [None, None]] Но если вы присвоите значение, то оно появится в нескольких местах: >>> A[ 0 ][ 0 ] = 5 >>> A [[5, None], [5, None], [5, None]] Причина в том, что оператор * не создаёт копию, а только ссылку на существующий объ- ект. *3 создаёт список из 3 ссылок на один и тот же список. Изменение в одной строке изменяют другие, что, вероятно, не то, что вы хотите. Возможные пути решения: A = [ None ] * 3 for i in range ( 3 ): A[i] = [ None ] * 2 w, h = 2 , 3 A = [[ None ] * w for i in range (h)] Или, можно использовать специальные модули, предоставляющие матрицы. Наиболее известным является NumPy 33.19. Как удалить все символы новой строки в конце строки? 145 Самоучитель Python, Выпуск 0.2 Почему a_tuple[i] += [’item’] не работает, а добавление работа- ет? Это из-за того, что расширенный оператор присваивания - оператор присваивания, а так- же из-за разницы между изменяемыми и неизменяемыми объектами в Python. Это обсуждение относится в общем, когда расширенные операторы присваивания приме- няются к элементам кортежа, которые указывают на изменяемые объекты, но мы будем использовать список и +=, как образец. Если вы напишете: >>> a_tuple = ( 1 , 2 ) >>> a_tuple[ 0 ] += 1 Traceback (most recent call last): TypeError : 'tuple' object does not support item assignment Причина исключения должна быть понятна: 1 добавляется к объекту a_tuple[0], но ко- гда мы пытаемся присвоить результат, 2, к первому элементу в кортеже, мы получаем ошибку, поскольку мы не можем изменить элемент кортежа. То есть, это выражение делает следующее: >>> result = a_tuple[ 0 ] + 1 >>> a_tuple[ 0 ] = result Traceback (most recent call last): TypeError : 'tuple' object does not support item assignment Когда мы пишем что-то вроде: >>> a_tuple = ([ 'foo' ], 'bar' ) >>> a_tuple[ 0 ] += [ 'item' ] Traceback (most recent call last): TypeError : 'tuple' object does not support item assignment Исключение немного более неожиданное, но более удивителен тот факт, что, несмотря на ошибку, элемент добавился! >>> a_tuple[ 0 ] ['foo', 'item'] Чтобы понять, что случилось, нужно знать, что: • Если объект определяет метод __iadd__, он вызывается, когда выполняется +=, и воз- вращенное значение используется для присваивания • Для списков, __iadd__ эквивалентен вызову extend для списка Таким образом, 33.22. Почему a_tuple[i] += [’item’] не работает, а добавление работает? 146 Самоучитель Python, Выпуск 0.2 >>> a_list = [] >>> a_list += [ 1 ] >>> a_list [1] Эквивалентен: >>> result = a_list __iadd__ ([ 1 ]) >>> a_list = result Таким образом, наш пример с кортежом эквивалентен: >>> result = a_tuple[ 0 ] __iadd__ ([ 'item' ]) >>> a_tuple[ 0 ] = result Traceback (most recent call last): TypeError : 'tuple' object does not support item assignment __iadd__ завершился успешно, и список увеличился, но присваивание законилось ошиб- кой. 33.22. Почему a_tuple[i] += [’item’] не работает, а добавление работает? 147 Глава 34 Задачи по Python Каждому изучающему Python нужно писать код для закрепления. Вашему вниманию предлагаются несколько задач для реализации (не слишком простых (кроме первой) и не слишком сложных). Для выполнения заданий крайне рекомендуется пройти самоучитель Также для этих задач есть репозиторий с тестами и моими решениями (чтобы проверить себя). Для запуска тестов для вашей функции проще всего будет добавить код из папки с теста- ми в конец файла с функцией. А теперь, собственно, задачи: Простейшие арифметические операции (1) Написать функцию arithmetic, принимающую 3 аргумента: первые 2 - числа, третий - операция, которая должна быть произведена над ними. Если третий аргумент +, сложить их; если --, то вычесть; * — умножить; / — разделить (первое на второе). В остальных случаях вернуть строку “Неизвестная операция”. Високосный год (2) Написать функцию is_year_leap, принимающую 1 аргумент — год, и возвращающую True, если год високосный, и False иначе. 148 Самоучитель Python, Выпуск 0.2 Квадрат (3) Написать функцию square, принимающую 1 аргумент — сторону квадрата, и возвраща- ющую 3 значения (с помощью кортежа ): периметр квадрата, площадь квадрата и диаго- наль квадрата. Времена года (4) Написать функцию season, принимающую 1 аргумент — номер месяца (от 1 до 12), и воз- вращающую время года, которому этот месяц принадлежит (зима, весна, лето или осень). Банковский вклад (5) Пользователь делает вклад в размере a рублей сроком на years лет под 10% годовых (каж- дый год размер его вклада увеличивается на 10%. Эти деньги прибавляются к сумме вкла- да, и на них в следующем году тоже будут проценты). Написать функцию bank, принимающая аргументы a и years, и возвращающую сумму, которая будет на счету пользователя. Простые числа (6) Написать функцию is_prime, принимающую 1 аргумент — число от 0 до 1000, и возвра- щающую True, если оно простое, и False - иначе. Правильная дата (7) Написать функцию date, принимающую 3 аргумента — день, месяц и год. Вернуть True, если такая дата есть в нашем календаре, и False иначе. XOR-шифрование (8) Написать функцию XOR_cipher, принимающая 2 аргумента: строку, которую нужно за- шифровать, и ключ шифрования, которая возвращает строку, зашифрованную путем применения функции XOR (^) над символами строки с ключом. Написать также функ- цию XOR_uncipher, которая по зашифрованной строке и ключу восстанавливает исход- ную строку. 34.3. Квадрат (3) 149 |