Поиск частичных строк в списке строк — python

Я пытаюсь проверить, является ли пользователь членом группы Active Directory, и у меня есть это:

ldap.set_option(ldap.OPT_REFERRALS, 0)
try:
  con = ldap.initialize(LDAP_URL)
  con.simple_bind_s(userid+"@"+ad_settings.AD_DNS_NAME, password)
  ADUser = con.search_ext_s(ad_settings.AD_SEARCH_DN, ldap.SCOPE_SUBTREE, \  
           "sAMAccountName=%s" % userid, ad_settings.AD_SEARCH_FIELDS)[0][1]
except ldap.LDAPError:
  return None

ADUser возвращает список строк:

{'givenName': ['xxxxx'],
 'mail': ['[email protected]'],
 'memberOf': ['CN=group1,OU=Projects,OU=Office,OU=company,DC=domain,DC=com',
              'CN=group2,OU=Projects,OU=Office,OU=company,DC=domain,DC=com',
              'CN=group3,OU=Projects,OU=Office,OU=company,DC=domain,DC=com',
              'CN=group4,OU=Projects,OU=Office,OU=company,DC=domain,DC=com'],
 'sAMAccountName': ['myloginid'],
 'sn': ['Xxxxxxxx']}

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

Если я получу список групп как ADUser.get('memberOf')[0], как лучше всего проверить, существуют ли какие-либо члены отдельного списка в основном списке?

Например, контрольный список будет ['group2', 'group16'], и я хочу получить ответ "истина/ложь" относительно того, существует ли какой-либо меньший список в основном списке.


person Technical Bard    schedule 07.07.2009    source источник


Ответы (2)


Если приведенный вами пример формата несколько надежен, например:

import re
grps = re.compile(r'CN=(\w+)').findall

def anyof(short_group_list, adu):
  all_groups_of_user = set(g for gs in adu.get('memberOf',()) for g in grps(gs))
  return sorted(all_groups_of_user.intersection(short_group_list))

где вы передаете свой список, такой как ['group2', 'group16'], в качестве первого аргумента, ваш ADUser dict в качестве второго аргумента; это возвращает отсортированный по алфавиту список (возможно, пустой, что означает «нет») групп, среди тех, что в short_group_list, к которым принадлежит пользователь.

Вероятно, это не намного быстрее, чем просто логическое значение, но, если вы настаиваете, изменив второй оператор функции на:

  return any(g for g in short_group_list if g in all_groups_of_user)

может сэкономить определенное количество времени в «истинном» случае (поскольку any короткое замыкание), хотя я подозреваю, что не в «ложном» случае (где в любом случае должен быть пройден весь список). Если вас волнует проблема производительности, лучше всего сравнить обе возможности на данных, которые реалистичны для вашего варианта использования!

Если производительность еще недостаточно высока (и, как вы говорите, логического да/нет достаточно), попробуйте изменить логику цикла:

def anyof_v2(short_group_list, adu):
  gset = set(short_group_list)
  return any(g for gs in adu.get('memberOf',()) for g in grps(gs) if g in gset)

Возможности короткого замыкания any могут оказаться здесь более полезными (по крайней мере, в «истинном» случае, опять же — потому что, опять же, нет никакого способа дать «ложный» результат, не изучив ВСЕ возможности в любом случае!-).

person Alex Martelli    schedule 08.07.2009
comment
Определение anyof() с логическим возвратом идеально. поиск по списку быстрее, чем задержка сети, чтобы получить список в первую очередь, поэтому производительность в порядке. - person Technical Bard; 08.07.2009

Вы можете использовать пересечение set (оператор &) после того, как вы проанализируете список групп. Например:

> memberOf = 'CN=group1,OU=Projects,OU=Office,OU=company,DC=domain,DC=com'

> groups = [token.split('=')[1] for token in memberOf.split(',')]

> groups
['group1', 'Projects', 'Office', 'company', 'domain', 'com']

> checklist1 = ['group1', 'group16']

> set(checklist1) & set(groups)
set(['group1'])

> checklist2 = ['group2', 'group16']

> set(checklist2) & set(groups)
set([])

Обратите внимание, что условное вычисление множества работает так же, как и для списков и кортежей. True, если в наборе есть какие-либо элементы, в противном случае — False. Таким образом, "if set(checklist2) & set(groups): ..." не будет выполняться, поскольку в приведенном выше примере условие оценивается как False (противоположное верно для теста checklist1).

Также см:

http://docs.python.org/library/sets.html

person ars    schedule 07.07.2009