Отладка

Это самая важная вещь для глубокого изучения и понимания конкретного языка. Разработчик должен понимать, как работает код, как реализована библиотека, используя инструмент отладки для проверки вызова функции, переменных и логики.

>>> def hanoi_population(list_populations):
    import pdb; pdb.set_trace()
    big_city_populations = [population for population in     list_populations if population > 1000]
    return round(sum(big_city_populations), 2)
>>> hanoi_population([10000, 20000, 100])
> <ipython-input-7-1e8b6f117387>(3)hanoi_population()
-> big_city_populations = [population for population in     list_populations if population > 1000]
(Pdb) h 
Documented commands (type help <topic>):
========================================
EOF    bt         cont      enable  jump  pp       run      unt
a      c          continue  exit    l     q        s        until
alias  cl         d         h       list  quit     step     up
args   clear      debug     help    n     r        tbreak   w
b      commands   disable   ignore  next  restart  u        whatis
break  condition  down      j       p     return   unalias  where
Miscellaneous help topics:
==========================
exec  pdb
Undocumented commands:
======================
retval  rv

Показать все команды, нажав h или help после (Pdb)

  • Одной из любимых команд для отладки является команда DIR (показывает все атрибуты и методы, связанные с объектом).
>>> numbers = [1, 2, 3, 4, 1, 2]
>>> dir(numbers)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

*args и **kwargs

Эти списки аргументов не распространены в вашем коде, но они часто используются в библиотеке и фреймворке.

1. *аргументы

  • список аргументов (пример: 1, «привет, Джо», объект, 1.23)
  • Как получить содержимое *args: доступ по индексу (например: args[0], args[1])
>>> def print_my_arguments(*args):
    for arg in args:
        print arg
>>> print_my_arguments(1, 'Hello Joe', 3)
1
Hello Joe
3

2. **кварг

  • аргументы с ключевыми словами (пример: message='Hello Joe', is_developer=True, member=member_object)
  • Как получить содержимое **kwargs: kwargs работает как dict (например: kwargs.get(‘message’) или kwargs[‘message’]
>>> def print_my_keyworded_arguments(**kwargs):
    for key, value in kwargs.items():
        print key, ":", value
>>> print_my_keyworded_arguments(message='Hello Joe', age=27)
message : Hello Joe
age : 27

3. Использование как *args, так и **kwargs

  • В основном *args и **kwargs используются для декораторов функций.
  • Обезьянье исправление (используемое для изменения некоторого кода во время выполнения) также является хорошим способом использования этого
  • Если вы хотите иметь достаточную гибкость для аргументов вашей функции (как список аргументов, так и аргументы с ключевыми словами)

Словарь

Это мой любимый трюк, словарь мощный и простой в использовании

  • Если слишком много предложений if/else =› с использованием словаря
  • Если для ключа должно быть значение по умолчанию => используйте setdefault
>>> def count_duplicates(numbers):
    result = {}
    for number in numbers:
        if number not in result:  # No need for if here
            result[key] = 0
        result[number] += 1
    return result
We can rewrite the function with setdefault
>>> def count_duplicates(numbers):
    result = {}
    for number in numbers:
        result.setdefault(number, 0)  # this is clearer
        result[number] += 1
    return result
  • Словарь для списка: items()
>>> a_dict = {'a': 1, 'b': 2}
>>> a_dict.items() 
[('a', 1), ('b', 2)]
  • Список в словарь
>>> a_list = [['a', 1], ['b', 2], ['c', 3]]
>>> dict(a_list)
{'a': 1, 'b': 2, 'c': 3}
  • Инвертирующий словарь
>>> a_dict = {'a': 1, 'b': 2, 'c': 3}
>>> invert_a_dict = {v: k for k, v in a_dict.iteritems()}
>>> invert_a_dict
{1: 'a', 2: 'b', 3: 'c'}
  • Избегайте KeyError в словаре => Использование defaultdict коллекций
>>> a_dict = {'a': 1}
>>> a_dict['b']
KeyError: 'b'
>>> from collections import defaultdict
>>> a_default_dict = defaultdict(list)
>>> a_default_dict['a'] 
[]
>>> from collections import defaultdict
>>> a_default_dict

Функция

  • Каждый раз, когда вы обнаружите, что постоянно пишете один и тот же/похожий код, вы слишком много работаете => используйте функцию шаблона.
  • Функция-оболочка (и декораторы) — один из лучших фокусов
>>> def update_phone_number(member, phone):
    member.phone = phone
    member.save()
This is a simple function that update the phone number for a member. However, I realise that 
* I want to check if them member has permission to change phone or not
* and I also want to keep the permission function out of my method above.
@permission
def update_phone_number(member, phone):
    member.phone = phone
    member.save()
def permission(func):
    def validate(*args, **kwargs):
        if not member.has_permission()
            raise Exception('Not permitted to change phone')
        return func(*args, **kwargs)
    return validate

Модульный тест

  • Напишите модульный тест для успеха/неудачи/исключения, чтобы убедиться, что ваша программа работает правильно, как и ожидалось.
  • Пример: сохраните содержимое в файл с именем test_python.py и запустите python test_python.py на терминале.
import unittest

def crease_one(x):
    return x + 1

class MyTest(unittest.TestCase):
    def test(self):
        self.assertEqual(increase_one(3), 4)
if __name__ == '__main__':
    unittest.main()

Подборки

  • Это полезный пакет Python, который мы могли бы часто использовать.
  • defaultdict/deque/namedtuple/counter/OrderedDict
>>> from collections import Counter
>>> numbers = [1, 2, 3, 4, 1, 2]
>>> counter = Counter(number for number in numbers)
>>> print counter
Counter({1: 2, 2: 2, 3: 1, 4: 1})