Если вы хотите разницу рекурсивно, я написал пакет для python: https://github.com/seperman/deepdiff
Установить из PyPi:
pip install deepdiff
Импорт
>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2
Тот же объект возвращает пустой
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}
Изменен тип элемента
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': ,
'newvalue': '2',
'oldtype': ,
'oldvalue': 2}}}
Значение элемента изменилось
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
Добавлен элемент и / или удален
>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
'dic_item_removed': ['root[4]'],
'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
Разность строк
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
"root[4]['b']": { 'newvalue': 'world!',
'oldvalue': 'world'}}}
Разница в строках 2
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
'+++ \n'
'@@ -1,5 +1,4 @@\n'
'-world!\n'
'-Goodbye!\n'
'+world\n'
' 1\n'
' 2\n'
' End',
'newvalue': 'world\n1\n2\nEnd',
'oldvalue': 'world!\n'
'Goodbye!\n'
'1\n'
'2\n'
'End'}}}
>>>
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
---
+++
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
1
2
End
Изменение типа
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': ,
'newvalue': 'world\n\n\nEnd',
'oldtype': ,
'oldvalue': [1, 2, 3]}}}
Разница в списке
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}
Переменная списка 2 :
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
"root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}
Разница в списке игнорирует порядок или дубликаты: (с теми же словарями, что и выше)
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}
Список, содержащий словарь:
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}
Наборы:
>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}
Именованные кортежи:
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}
Пользовательские объекты:
>>> class ClassA(object):
... a = 1
... def __init__(self, b):
... self.b = b
...
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>>
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
Добавлен атрибут объекта:
>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
Два способа обработки ошибок,
Я создаю хрупкий проект JS, который использует jquery-jsonp, и придумал подход с двойным jsonp / ajax, который обрабатывает ошибки независимо от того, какой метод заканчивается.
function authenticate(user, pass) {
var ajax = ($.jsonp || $.ajax)({
'url': /* your auth url */,
'data': { /* user, pass, ... */ },
'contentType': "application/javascript",
'dataType': 'jsonp',
'callbackParameter': 'callback' // $.jsonp only; $.ajax uses 'jsonpCallback'
});
ajax.done(function (data) {
// your success events
});
ajax.fail(function (jqXHR, textStatus, errorThrown) {
// $.jsonp calls this func as function (jqXHR, textStatus)
// and $.ajax calls this func with the given signature
console.error('AJAX / JSONP ' + textStatus + ': ' +
(errorThrown || jqXHR.url));
});
}
Поскольку jquery-jsonp и $ .ajax поддерживают спецификацию jQuery Deferred, мы можем объединить два обработчика ошибок вместе, обрабатывая ошибки 400 и 500, а также таймауты поиска.
Если вы проверите jQuery.ajax () документацию , вы можете найти:
error
Функция, которая будет вызываться, если запрос fail (...) Примечание. Этот обработчик не вызывается для междоменного скрипта и междоменных запросов JSONP. Это событие Ajax.
blockquote>Из-за этого вы вынуждены искать обходное решение. Вы можете указать время ожидания, чтобы вызвать обратный вызов ошибки. Это означает, что в течение заданного периода времени запрос должен быть успешно завершен. В противном случае предположим, что он потерпел неудачу:
$.ajax({ ... timeout: 5000, // a lot of time for the request to be successfully completed ... error: function(x, t, m) { if(t==="timeout") { // something went wrong (handle it) } } });
Другие проблемы в вашем коде ...
Пока JSONP (посмотрите здесь ] и здесь ) можно использовать для преодоления ограничения политики происхождения, вы не можете использовать POST с помощью JSONP (см. CORS ), потому что это просто не работает way - он создает элемент для извлечения данных, который должен выполняться с помощью запроса GET. Решение JSONP не использует объект XmlHttpRequest, поэтому он не является запросом AJAX в стандартном способе понимания, но контент по-прежнему доступен динамически - никакой разницы для конечного пользователя.
$.ajax({ url: url, type: "GET" dataType: "jsonp", ...
Во-вторых, вы предоставляете данные некорректно. Вы нажимаете javascript-объект (созданный с использованием объектных литералов) на провод вместо его сериализованного представления JSON. Создайте строку JSON (не вручную, используйте, например, преобразователь
JSON.stringify
):$.ajax({ ... data: JSON.stringify({u: userid, p: pass}), ...
В последнем выпуске вы установили
async
вfalse
, а в документации указано:Запросы междоменных и dataType: запросы «jsonp» не поддерживают синхронную работу.
blockquote>
timeout
: In Firefox 3.0+ only, script and JSONP requests cannot be cancelled by a timeout; the script will run even if it arrives after the timeout period.
– Tim McClure
9 July 2015 в 12:51
Старый вопрос, но у меня была та же проблема. Вот решение, которое сработало для меня.
Если у вас есть домен, на который вы снимаете свой запрос, вы можете установить переменную в ответе и проверить ее на стороне клиента.
Сторона сервера:
SERVER_RESPONSE=true; Callback(parameter1, parameter2);
Сторона клиента:
if(typeof SERVER_RESPONSE === 'undefined'){
console.log('No Response, maybe server is down');
}
else{
console.log('Got a server response');
}
Я пытался изо всех сил пытаться обрабатывать ошибки в запросах ajax jsonp DataType, однако я хочу поделиться с вами своим кодом, надеюсь, что это поможет. Основная вещь заключается в том, чтобы включить таймаут в запрос ajax, иначе он никогда не войдет в ошибку: function
$.ajax({
url: "google.com/api/doesnotexists",
dataType: "jsonp",
timeout: 5000,
success: function (parsed_json) {
console.log(parsed_json);
},
error: function (parsedjson, textStatus, errorThrown) {
console.log("parsedJson: " + JSON.stringify(parsedjson));
$('body').append(
"parsedJson status: " + parsedjson.status + '</br>' +
"errorStatus: " + textStatus + '</br>' +
"errorThrown: " + errorThrown);
}
});
jsfiddle - обрабатывать ошибки с помощью jquery ajax-вызова и JSONP dataType - ошибка 404
http://fiddle.jshell.net/_display/google.com
вместо google.com
. Если вы префикс url с помощью http
, вы увидите правильное поведение, когда наблюдается тайм-аут и статус не возвращается.
– Mig
25 March 2015 в 11:55