Home > Mobile >  Can you explain what happens here (gmail dot trick generator)
Can you explain what happens here (gmail dot trick generator)

Time:09-05

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))
  • Related