What is `1..__truediv__` ? Does Python have a .. (“dot dot”) notation syntax?

后端 未结 4 1953
死守一世寂寞
死守一世寂寞 2020-12-22 23:33

I recently came across a syntax I never seen before when I learned python nor in most tutorials, the .. notation, it looks something like this:

         


        
4条回答
  •  被撕碎了的回忆
    2020-12-22 23:46

    The question is already sufficiently answered (i.e. @Paul Rooneys answer) but it's also possible to verify the correctness of these answers.

    Let me recap the existing answers: The .. is not a single syntax element!

    You can check how the source code is "tokenized". These tokens represent how the code is interpreted:

    >>> from tokenize import tokenize
    >>> from io import BytesIO
    
    >>> s = "1..__truediv__"
    >>> list(tokenize(BytesIO(s.encode('utf-8')).readline))
    [...
     TokenInfo(type=2 (NUMBER), string='1.', start=(1, 0), end=(1, 2), line='1..__truediv__'),
     TokenInfo(type=53 (OP), string='.', start=(1, 2), end=(1, 3), line='1..__truediv__'),
     TokenInfo(type=1 (NAME), string='__truediv__', start=(1, 3), end=(1, 14), line='1..__truediv__'),
     ...]
    

    So the string 1. is interpreted as number, the second . is an OP (an operator, in this case the "get attribute" operator) and the __truediv__ is the method name. So this is just accessing the __truediv__ method of the float 1.0.

    Another way of viewing the generated bytecode is to disassemble it. This actually shows the instructions that are performed when some code is executed:

    >>> import dis
    
    >>> def f():
    ...     return 1..__truediv__
    
    >>> dis.dis(f)
      4           0 LOAD_CONST               1 (1.0)
                  3 LOAD_ATTR                0 (__truediv__)
                  6 RETURN_VALUE
    

    Which basically says the same. It loads the attribute __truediv__ of the constant 1.0.


    Regarding your question

    And how can you use it in a more complex statement (if possible)?

    Even though it's possible you should never write code like that, simply because it's unclear what the code is doing. So please don't use it in more complex statements. I would even go so far that you shouldn't use it in so "simple" statements, at least you should use parenthesis to separate the instructions:

    f = (1.).__truediv__
    

    this would be definetly more readable - but something along the lines of:

    from functools import partial
    from operator import truediv
    f = partial(truediv, 1.0)
    

    would be even better!

    The approach using partial also preserves python's data model (the 1..__truediv__ approach does not!) which can be demonstrated by this little snippet:

    >>> f1 = 1..__truediv__
    >>> f2 = partial(truediv, 1.)
    
    >>> f2(1+2j)  # reciprocal of complex number - works
    (0.2-0.4j)
    >>> f2('a')   # reciprocal of string should raise an exception
    TypeError: unsupported operand type(s) for /: 'float' and 'str'
    
    >>> f1(1+2j)  # reciprocal of complex number - works but gives an unexpected result
    NotImplemented
    >>> f1('a')   # reciprocal of string should raise an exception but it doesn't
    NotImplemented
    

    This is because 1. / (1+2j) is not evaluated by float.__truediv__ but with complex.__rtruediv__ - operator.truediv makes sure the reverse operation is called when the normal operation returns NotImplemented but you don't have these fallbacks when you operate on __truediv__ directly. This loss of "expected behaviour" is the main reason why you (normally) shouldn't use magic methods directly.

提交回复
热议问题