2016-06-21 3 views
0

Я хотел бы использовать operator.attrgetter и itertool.groupby, чтобы разделить строку текста пробелами, сохраняя количество пробелов между текстом. Это ожидаемое поведение:Отрицание `operator.attrgetter`

result = process('Am     G   C') 
assert result == [(2, 'Am'), (20, ' '), (1, 'G'), (10, ' '), (1, 'C')] 

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

text = '''Am     G   C''' 
processed=((k, list(l))for k, l in groupby(text, attrgetter("isspace"))) 
result = [(len(l), "".join(l)) if k else (len(l), " ") for k, l in processed] 

Но это вернет:

[(1, 'A'), (1, 'm'), (20, '     '), (1, 'G'), (10, '   '), (1, 'C')] 

Что мне нужно, хотя, как раз наоборот, и я попытался:

from operator import neg, attrgetter 
text = '''Am     G   C''' 
processed = ((k,list(l)) for k,l in groupby(text, neg(attrgetter("isspace")))) 
result = [(len(l), "".join(l)) if k else (len(l), " ") for k, l in processed] 

Это бросает:

TypeError: bad operand type for unary -: 'operator.attrgetter'

Как я могу отменить значение, возвращаемое с attrgetter для ключевых целей?

+2

Просто напишите свою собственную функцию, чтобы инвертировать ее и использовать. – jonrsharpe

+1

Я думаю, что ближе всего вы получите, не прибегая к лямбда, это '' ".__ ne__'. –

+0

В этом конкретном вопросе вам действительно не нужно отменять функцию здесь, просто отрицайте условие в выражении if/else. Поэтому 'x, если y else z' становится' x, если не y else z'. например. 'result = [(len (l)", ".join (l)), если не k else (len (l)," ") для k, l в обработанном виде]. Вы также можете использовать 'str.isspace' над' attrgetter ("isspace") '. – Dunes

ответ

4

operator.attrgetter не будет непосредственно работать в качестве ключевой функции здесь. attrgetter("isspace")(x) просто принести атрибут x"isspace", а также необходимо назвать:

>>> attrgetter("isspace")(" ") 
<built-in method isspace of str object at 0x7f30c4301ab0> 
>>> attrgetter("isspace")(" ")() 
True 

Вы можете использовать str.isspace вместо:

>>> processed = ((k, list(l)) for k, l in groupby(text, str.isspace)) 
>>> result = [(len(l), " ") if k else (len(l), "".join(l)) for k, l in processed] 
>>> result 
[(2, 'Am'), (20, ' '), (1, 'G'), (10, ' '), (1, 'C')] 
2

Нет, вы не можете сделать перевернутую функцию в attrgetter , или любую другую функцию с оператором neg. Прежде всего, neg означает отрицание; например neg(x) < =>-x. И это относится к False результатов: 0; True =>-1. Булево отрицание - operator.not_. Но даже тогда это мало помогло бы вам свести на нет обратную стоимость - и даже отвращение не помогло бы вам.

Вместо этого вы должны просто пройти в str.isspace до groupby; str.ispace - это несвязанный метод, который принимает аргумент типа str.

Вы видите здесь, что возвращаемое значение attrgetter('isspace') вызывается с каждым отдельным символом в качестве значения. Каждый вызов возвращает метод в связанного экземпляра:

>>> attrgetter('isspace')('a') 
<built-in method isspace of str object at 0x7fb204de5110> 

Поскольку каждый из этих связанных методов, связанных с другим экземпляром, они обязательно отличаются друг от друга, и не равный друг друг, поэтому ваш код не делает то, что вы ожидаете. Для того, чтобы получить фактическое значение, вы должны вызова этот метод еще раз:

>>> attrgetter('isspace')('a') 
False 

В этом случае я бы угробить itertools полностью. Это задача только для текста, поэтому регулярные выражения и модуль re - это путь.

Там нет необходимости даже обрабатывать этот символ за символом, когда re.split собирается уже достичь 90% того, что вы хотите:

>>> import re 
>>> s = 'Am     G   C' 
>>> parts = re.split('(\s+)', s) 
>>> parts 
['Am', '     ', 'G', '   ', 'C'] 

Затем просто использовать список понимание, чтобы сделать их в длину , струнные кортежи:

>>> [(len(i), i) for i in parts] 
[(2, 'Am'), (20, '     '), (1, 'G'), (10, '   '), (1, 'C')] 

То есть, re.split расщепляется по данному регулярному выражению. \s+ соответствует одному или нескольким символам пробела. Обычно разделитель отбрасывается, но если регулярное выражение содержит подгруппу (...), то содержимое этой подгруппы также сохраняется в матче.

+0

Это на самом деле гораздо более читаемое решение. Спасибо. –

Смежные вопросы