Created
March 22, 2014 05:08
-
-
Save vartagg/9701590 to your computer and use it in GitHub Desktop.
Различные утилиты
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def deep_dict_merge(a, b): | |
""" | |
Объединение словарей, которые могут содержать внутри | |
себя другие словари. При совпадении ключей приоритет | |
имеет словарь b (предполагается, что он содержит более актуальные данные). | |
:param a: dict | |
:param b: dict | |
>>> a = {1: {'a': 'A'}, 2:{'b': 'B'}} | |
>>> b = {2:{'c': 'C'}, 3: {'d': 'D'}} | |
>>> deep_dict_merge(a, b) | |
{1: {'a': 'A'}, 2: {'c': 'C', 'b': 'B'}, 3: {'d': 'D'}} | |
>>> a = {1: {'a':'F'}, 2: {'b': 'B'}, 3:'X'} | |
>>> b = {1: {'a': 'A'}, 2:{'b': 'C'}} | |
>>> deep_dict_merge(a, b) | |
{1: {'a': 'A'}, 2: {'b': 'C'}, 3: 'X'} | |
""" | |
for key in b.keys(): | |
if key in a: | |
if isinstance(a[key], dict) and isinstance(b[key], dict): | |
deep_dict_merge(a[key], b[key]) | |
elif a[key] == b[key]: | |
pass | |
else: | |
a[key] = b[key] | |
else: | |
a[key] = b[key] | |
return a | |
def extract_value_from_multidict(dct, keys_queue): | |
""" | |
Извлекает из Мульти-словаря (т.е. словаря, который содержит внутри себя другие словари), | |
значение на определенном уровне вложенности, порядок которого задает очередь ключей keys_queue. | |
Возвращает None, если данное значение отстутствует на этом уровне вложенности | |
:param dct: dict | |
:param keys_queue: list | |
>>> d = {'a': {'b': {'c': 10}}} | |
>>> extract_value_from_multidict(d, ['a', 'b', 'c']) | |
10 | |
>>> d = {'a': {'b': {'c': 0}}} | |
>>> res = extract_value_from_multidict(d, ['a', 'b', 'c']) | |
>>> res is None | |
True | |
>>> d = {'a': {'x': {'c': 1}}} | |
>>> res = extract_value_from_multidict(d, ['a', 'b', 'c']) | |
>>> res is None | |
True | |
>>> d = {'a': {'b': 13}} | |
>>> res = extract_value_from_multidict(d, ['a', 'b', 'c']) | |
>>> res is None | |
True | |
""" | |
for k in keys_queue: | |
if not dct.get(k): | |
return None | |
if not isinstance(dct[k], dict): | |
if not keys_queue[1:]: | |
return dct[k] | |
return None | |
return extract_value_from_multidict(dct[k], keys_queue[1:]) | |
def dict_segment(dct, subset): | |
""" | |
Возвращает словарь, который является частью исходного словаря. | |
В случае отсутствия какого-либо ключа в исходном словаре, | |
создает этот ключ и устанавливает у него значение None. | |
:param dct: dict | |
:param subset: list | |
>>> a = {'x': 1, 'y': 2, 'z': 3} | |
>>> dict_segment(a, ['x', 'y']) | |
{'y': 2, 'x': 1} | |
>>> a = {'y': 2, 'z': 3} | |
>>> dict_segment(a, ['x', 'y']) | |
{'y': 2, 'x': None} | |
""" | |
return {k: dct.get(k) for k in subset} | |
def dict_union(d1, d2): | |
""" | |
Объединяет 2 словаря. Ключи у словарей не должны пересекаться | |
:param d1: dict | |
:param d2: dict | |
""" | |
return dict(d1.items() + d2.items()) | |
def chunks(l, n): | |
""" Генератор, разбивает исходный список l на список списков, каждый из которых | |
будет размером, не большим чем n. | |
>>> a = [i for i in range(10)] | |
>>> [i for i in chunks(a, 5)] | |
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]] | |
>>> a = [i for i in range(7)] | |
>>> [i for i in chunks(a, 5)] | |
[[0, 1, 2, 3, 4], [5, 6]] | |
""" | |
for i in xrange(0, len(l), n): | |
yield l[i:i+n] | |
class EmailsFinder(object): | |
""" | |
Этот класс используется для поиска адресов электронной почты среди информации, которую возвращают | |
социальные сети при авторизации. Поиск производжится в контейнере, который может содержать другие контейнеры. | |
Внешним контейнером должен быть словарь. | |
Все остальные контейнеры - это словари либо списки. | |
Возвращает список кортежей, в каждом из которых первый элемент - это код социальной сети, а второй - email. | |
Также его можно использовать для простой проверки на email | |
""" | |
class RealNone(object): | |
pass | |
def __init__(self, start_container): | |
""" | |
>>> c = {'q': [2,'a@a.a', {'tw': {'bw': 'b@b.b'}}, 65], 'a': 'f', 'b': 1, 'c': [1, 15, 'ex@example.com', {'rt': 1, 'ew': '.@', 'pf': '@', 'g': 'g@example.com'}], 'we': 'g2@example.com'} | |
>>> ef = EmailsFinder(c) | |
>>> ef.find() | |
[('q', 'a@a.a'), ('c', 'g@example.com'), ('c', 'ex@example.com'), ('q', 'b@b.b'), ('we', 'g2@example.com')] | |
>>> EmailsFinder.check_email('ex@example.com') | |
True | |
""" | |
self.start_container = start_container | |
@staticmethod | |
def check_email(peace): | |
"""Простая проверка на email""" | |
if isinstance(peace, basestring): | |
monkey_place = peace.find('@') | |
dot_place = peace.find('.') | |
if -1 not in (monkey_place, dot_place) and monkey_place < dot_place: | |
return True | |
return False | |
def find(self): | |
emails = set() | |
for email in self.emails_finder(self.start_container, self.RealNone): | |
emails.add(email) | |
return list(emails) | |
def emails_finder(self, foo, parent): | |
if isinstance(foo, dict): | |
for key, elem in foo.items(): | |
if parent is self.RealNone: | |
self.parent = key | |
for each in self.emails_finder(elem, key): | |
yield each | |
elif isinstance(foo, list): | |
for elem in foo: | |
for each in self.emails_finder(elem, parent): | |
yield each | |
else: | |
if self.check_email(foo): | |
yield self.parent, foo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment