I literally don't understand
def dot_trick(handle):
f = lambda s:s[11:] and [s[0] w x for x in f(s[1:]) for w in('.','')] or [s]
return f(handle)
found it on the internet, it generates all 'gmail dot trick' email variations
this seems like magic in such compact form, can someone explain me what happens here step by step, please? or maybe rephrase it without lambda function
CodePudding user response:
It mainly uses list comprehension and ternary operators implemented with binary operators
The pattern it uses it's deprecated, since the builtin syntax for the ternary operator has been introduced in PEP 308 on the release of Python 2.5
.
Furthermore
s[11:] and [s[0] w x for x in f(s[1:]) for w in('.','')] or [s]
can be split into:
def f(s)
if len(s[11:]) > 0:
lst = []
for w in (".",''):
for x in f(s[1:]): #s[:1] removes first character
lst.append(s[0] w x)
return lst
return [s]
here is what it shows with the libcst
library:
>>> print(libcst.tools.dump(cst.parse_expression("s[11:] and [s[0] w x for x in f(s[1:]) for w in('.','')] or [s]")))
BooleanOperation(
left=BooleanOperation(
left=Subscript(
value=Name(
value='s',
),
slice=[
SubscriptElement(
slice=Slice(
lower=Integer(
value='11',
),
upper=None,
),
),
],
),
operator=And(),
right=ListComp(
elt=BinaryOperation(
left=BinaryOperation(
left=Subscript(
value=Name(
value='s',
),
slice=[
SubscriptElement(
slice=Index(
value=Integer(
value='0',
),
),
),
],
),
operator=Add(),
right=Name(
value='w',
),
),
operator=Add(),
right=Name(
value='x',
),
),
for_in=CompFor(
target=Name(
value='x',
),
iter=Call(
func=Name(
value='f',
),
args=[
Arg(
value=Subscript(
value=Name(
value='s',
),
slice=[
SubscriptElement(
slice=Slice(
lower=Integer(
value='1',
),
upper=None,
),
),
],
),
),
],
),
inner_for_in=CompFor(
target=Name(
value='w',
),
iter=Tuple(
elements=[
Element(
value=SimpleString(
value="'.'",
),
),
Element(
value=SimpleString(
value="''",
),
),
],
),
),
),
),
),
operator=Or(),
right=List(
elements=[
Element(
value=Name(
value='s',
),
),
],
),
)
And here is what it prints for the ast builtin library:
>>> print(ast.dump(ast.parse("s[11:] and [s[0] w x for x in f(s[1:]) for w in('.','')] or [s]")))
Module(body=[Expr(value=BoolOp(op=Or(), values=[BoolOp(op=And(), values=[Subscript(value=Name(id='s', ctx=Load()), slice=Slice(lower=Constant(value=11)), ctx=Load()), ListComp(elt=BinOp(left=BinOp(left=Subscript(value=Name(id='s', ctx=Load()), slice=Constant(value=0), ctx=Load()), op=Add(), right=Name(id='w', ctx=Load())), op=Add(), right=Name(id='x', ctx=Load())), generators=[comprehension(target=Name(id='x', ctx=Store()), iter=Call(func=Name(id='f', ctx=Load()), args=[Subscript(value=Name(id='s', ctx=Load()), slice=Slice(lower=Constant(value=1)), ctx=Load())], keywords=[]), ifs=[], is_async=0), comprehension(target=Name(id='w', ctx=Store()), iter=Tuple(elts=[Constant(value='.'), Constant(value='')], ctx=Load()), ifs=[], is_async=0)])]), List(elts=[Name(id='s', ctx=Load())], ctx=Load())]))], type_ignores=[])
CodePudding user response:
This is how it could look like in a readable form:
def gen_dot_trick(handle):
if len(handle) <= 11:
# stop recursion at the last character of the user name
# 11 is the length of "[email protected]"
yield handle
else:
first, rest = handle[0], handle[1:]
for sub in gen_dot_trick(rest):
# with and without the dot after the first char
yield first '.' sub
yield first sub
def dot_trick(handle):
return list(gen_dot_trick(handle))