Форум сайта python.su
Есть очень большой (или просто большой) /etc/passwd файл, нужно из него очень быстро извлечь username по uid.
Быстро читать конечно нужно с помощью генератора. Но если например запись с самого начала то не оптимально далее дочитывать строки. От сюда вопрос как можно после получения первого значения прекратить/прервать генератор (по аналогии как это делается breack в простом цикле)?
def get_usrname(user_uid): passwd_file = open('/etc/passwd') user_name_list = [passwd_file_line.split(':')[0] for passwd_file_line in passwd_file if passwd_file_line.split(':')[2] == user_uid] return user_name_list[0] """ ## example /etc/passwd psaftp:x:505:506:anonftp psa user:/:/sbin/nologin apache:x:506:507:Apache server:/:/sbin/nologin drweb:x:100:511:DrWeb system account:/var/drweb:/bin/false webalizer:x:67:67:Webalizer:/var/www/usage:/sbin/nologin mailman:x:41:41:GNU Mailing List Manager:/usr/lib/mailman:/sbin/nologin ntp:x:38:38::/etc/ntp:/sbin/nologin named:x:25:25:Named:/var/named:/sbin/nologin sw-cp-server:x:507:512::/:/bin/true paveln:x:10000:509::/var/www/vhosts/localhost.localdomain:/bin/false nginx:x:498:497:Nginx user:/var/lib/nginx:/bin/false test3:x:10001:10001::/home/test3:/bin/bash test4:x:10002:10002::/home/test4:/bin/bash testuser:x:10003:10003::/home/testuser:/bin/bash testuser1:x:10003:10004::/home/testuser:/bin/bash """
Отредактировано agryn (Дек. 3, 2013 20:14:40)
Офлайн
Я так и не понял в чём у тебя проблема?
def get_usrname(user_uid): for x in open('/home/rodegast/pass'): if x.split(':')[2] == user_uid: return x.split(':')[0] print get_usrname("505")
user_uid = "506" print map(lambda x: x.split(':')[0], filter(lambda x:x.split(':')[2] == user_uid, open('/home/rodegast/pass')))
Офлайн
RodegastВот этот код нужно с помощью генератора для большой скорости.def get_usrname(user_uid): for x in open('/home/rodegast/pass'): if x.split(':')[2] == user_uid: return x.split(':')[0]
Офлайн
agrynНе знаю уж, какой скорости вы хотите добиться на сотне строк файла паролей. Но вам дали правильные вариант - файл читается построчно, до первого включения, а у вас как раз весь считывается в список :P
Вот этот код нужно с помощью генератора для большой скорости.
def first(ls, test): for x in ls: if test(x): return x def get_username(search_uid): with open('/etc/passwd') as inf: return first((passwd_file_line.split(':') for passwd_file_line in inf), lambda x: x[0] == search_uid)
Отредактировано PooH (Дек. 4, 2013 15:28:08)
Офлайн
agryn
Вообще-то генератор списков это просто “синтаксический сахар” и по реализации ничем не отличается, от обычного for. Следовательно он работает с такой же скоростью.
lst = [] for elem in xrange(10): lst.append(elem)
lst = [elem for elem in xrange(10)]
Отредактировано Budulianin (Дек. 4, 2013 16:31:56)
Офлайн
может вместо return использовать yield ? Может автор темы эту быстроту имеет ввиду?
http://savepic.ru/4976932.jpg
Офлайн
smoke853
может вместо return использовать yield ? Может автор темы эту быстроту имеет ввиду?
Офлайн
comprehension'ы оптимизируют как раз-таки полную генерацию списка и было бы грубо требовать от них наличие break'а.
Раз уж фп-тред
import operator as op split = lambda sep : lambda string : string.split(sep) def find(item, seq, test=op.eq, key=lambda elt : elt): for elt in seq: if test(item, key(elt)): return elt def get_username(uid): return find(uid, map(split(':'), open('/etc/passwd')), key=op.itemgetter(2))[0] print(get_username('10'))
Офлайн
В смысле какая скорость? в первом случае время выполнения = 0.755, во втором = 0.002, очевидно что второй вариант работает быстрее.
Офлайн
smoke853Долго думал, где же подвох)
В смысле какая скорость? в первом случае время выполнения = 0.755, во втором = 0.002, очевидно что второй вариант работает быстрее.
Офлайн