Skip to content

Instantly share code, notes, and snippets.

@vartagg
Created March 22, 2014 05:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vartagg/9701590 to your computer and use it in GitHub Desktop.
Save vartagg/9701590 to your computer and use it in GitHub Desktop.
Различные утилиты
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