在字符串列表中查找部分字符串 - 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': ['xxxxx@example.com'],
'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']
,我想知道这个小列表中的任何一个组是否存在于主列表中,结果是对还是错。
2 个回答
你可以在解析出组列表后,使用集合交集(& 操作符)。比如:
> 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 的测试结果正好相反)。
另外,你也可以查看:
如果你给出的格式示例比较可靠,比如:
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
字典作为第二个参数传入;这样会返回一个按字母顺序排列的列表(可能是空的,表示“没有”),这个列表包含了用户所属的那些在 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
的短路特性在这里可能会更有用(至少在“是”的情况下是这样,因为无论如何,要给出“否”的结果都必须检查所有可能性!)。