Начнем с объективных вещей:
Именованые параметры в методах c значениями по умолчанию
Чрезвычайно полезная возможность, с помощью которой ты забываешь что такое рефакторинг связанный с сигнатурой метода.
Пример: есть метод get объекта dict, который возвращает значение по ключу если оно есть, если его нет то возвращается значение по умолчанию.
Код на Java
public void V get(K key) {
return this.values.get(key);
}
public void V get(K key, V default) {
return this.values.get(key, default);
}
Код на python
def get(self, key, default=None):
return self.values.get(key, default)
Чем это хорошо? Давайте посмотрим на типичную эволюцию кода. Сначала у вас было все просто и значение по умолчанию возвращать было не нужно, потом в каком-то месте понадобилось вернуть значение по умолчанию. Что вы делаете в случае Java- либо добавляете метод, либо добавляете if-else блок вместо него и после 5-го такого блока таки добавляете метод и затеваете небольшой рефакторинг. В случае с python вы сразу же добавляете параметр со значением по умолчанию не нарушая прошлый код, просто потому что по другому никак, нет здесь перегрузки методов. Это простой пример, на практике встречаются функции с, например, 5 необязательными разнотипными параметрами и в случае Java это сводится к 2 ** 5 = 32 перегруженых функций, в python это все достигается одним методом И никакого рефакторинга.
*args, **kwargs - аргументы метода и именованные аргументы метода
Помимо возможности передать в метод аргументы которые объявлены в сигнатуре явно, в python вы имеете возможность передавать в метод все что захотите и, с другой стороны, доступаться к этим значениям внутри метода. Как это использовать?
Пример: вам нужно сделать метод который будет генерировать HTML тег IMG с набором аттрибутов, код на Java который это делает невозможен без передачи чего-то вроде hash map с набором аттрибутов (поправьте меня если я не прав) в итоге все выглядит так
Код на Java
public static String imageTag(Map attrs) {
StringBuffer res = new StringBuffer();
for (entry in attrs.entries()) {
res.append(String.format("%s='%s' ", entry.key(), entry.value()));
}
return String.format("<img %s/>", res);
}
.... Вызов метода
Mapattrs = new HashMap ();
attrs.put("src", "foo.gif");
attrs.put("width", "100");
attrs.put("height", "200")
attrs.put("alt", "бар натуральный")
out.write(Tags.imageTag(attrs));
Код на Python
def image_tag(**kwargs):
return "<img %s/>" % " ".join(["%s='%s'" % (k, v) for (k, v) in kwargs.items()])
.... Вызов метода
print image_tag(src="foo.gif", width=100, height=200, alt=u"бар натуральный")
3 строки вместо 13 всего, 1 строка вместо 6-ти для вызова, а аттрибутов у HTML тегов десятки. В байтах тоже метрика схожая.
Впечатляет? А теперь представьте что вы хотите задать размер по умолчанию 100 на 100 если он не задан.
код на Java
public static String imageTag(Map attrs) {
if (!attrs.hasKey("width")) {
attrs.put("width", "100")
}
if (!attrs.hasKey("height")) {
attrs.put("height", "100")
}
StringBuffer res = new StringBuffer();
for (entry in attrs.entries()) {
res.append(String.format("%s='%s' ", entry.key(), entry.value()));
}
return String.format("<img %s/>", res);
}
Код на Python (дважды спасибо Сергею за исправление)
def image_tag(**kwargs):
kwargs.setdefault('width', 100)
kwargs.setdefault('height', 100)
return "<img %s/>" % " ".join(["%s='%s'" % (k, v) for (k, v) in kwargs.items()"])
Мало того что дополнительного кода меньше он еще и быстрее читается, на что требуются минимальные знания языка.
Продолжение следует...