programing

1이 뭔데?__truediv__`?><<<<<python>>>><<<<python>>><<<python>>

prostudy 2022. 3. 28. 21:39
반응형

1이 뭔데?__truediv__`?><<<<<python>>>><<<<python>>><<<python>>

최근 파이썬을 배울 때나 대부분의 튜토리얼에서 본 적이 없는 구문을 접하게 되었다...표기법, 이것과 비슷한 것 같다.

f = 1..__truediv__ # or 1..__div__ for python 2

print(f(8)) # prints 0.125 

나는 그것이 (물론 더 길다는 것 빼고는) 정확히 똑같다고 생각했다.

f = lambda x: (1).__truediv__(x)
print(f(8)) # prints 0.125 or 1//8

하지만 내 질문은:

  • 어떻게 된 일일까요?
  • 이 두 개의 점이 실제로 의미하는 것은 무엇인가?
  • 어떻게 하면 좀 더 복잡한 문장으로 (가능하면) 쓸 수 있을까?

이렇게 하면 앞으로 코드 라인이 많이 절약될 겁니다...:)

당신이 가지고 있는 것은float후행 0이 없는 리터럴을 사용하면__truediv__의 방법.그것은 그 자체로 연산자가 아니다; 첫 번째 점은 플로트 값의 일부분이고, 두 번째 점은 물체 속성과 메서드에 접근하는 점 연산자다.

다음과 같이 하면 같은 경지에 도달할 수 있다.

>>> f = 1.
>>> f
1.0
>>> f.__floordiv__
<method-wrapper '__floordiv__' of float object at 0x7f9fb4dc1a20>

다른 예

>>> 1..__add__(2.)
3.0

여기 1.0에 2.0을 추가하면 3.0이 나온다.

그 문제는 이미 충분히 답변되어 있지만(즉, @Paul Rooney의 대답) 이러한 답변의 정확성을 검증하는 것도 가능하다.

기존 답변을 다시 요약해 봅시다...단일 구문 요소가 아니다!

소스 코드가 어떻게 "토큰" 상태인지 확인할 수 있다.이러한 토큰은 코드가 해석되는 방식을 나타낸다.

>>> 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__'),
 ...]

그래서 끈은1.숫자로 해석되며, 두 번째 숫자로 해석된다..OP( 연산자, 이 경우 "get attribute" 연산자) 및__truediv__메서드 이름이다.그럼 이건 그냥 접근하는거야__truediv__부유식 방법1.0.

생성된 바이트코드를 보는 또 다른 방법은 그것을 조립하는 것이다.이는 실제로 일부 코드가 실행될 때 수행되는 지침을 보여준다.

>>> 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

그건 기본적으로 똑같아.속성을 로드한다.__truediv__상수의1.0.


당신의 질문에 관하여

그리고 어떻게 하면 좀 더 복잡한 문장으로 (가능한 경우) 사용할 수 있을까?

비록 그렇게 코드를 쓰면 안 된다 하더라도, 단지 코드가 무엇을 하고 있는지 불명확하기 때문에.그러니 제발 좀 더 복잡한 진술에 쓰지 말아줘.나는 심지어 당신이 그렇게 "단순한" 문장에 그것을 사용해서는 안 될 정도로까지 할 것이다. 적어도 지시사항을 분리하기 위해서는 괄호를 사용해야 한다.

f = (1.).__truediv__

이것은 확실히 더 읽기 쉬울 것이다 - 그러나 다음과 같은 선에 따른 것이다.

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

더 좋을 거야!

접근 방법을 :partial또한 python의 데이터 모델(The)도 보존한다.1..__truediv__접근은 그렇지 않다!) 이 작은 조각에 의해 증명될 수 있는 것은:

>>> 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

왜하하면 되기 때문이다.1. / (1+2j)평가되지 않음float.__truediv__을 가지고는complex.__rtruediv__-operator.truediv정상 작동이 반환될 때 역방향 작동이 호출되는지 확인NotImplemented이 하만지망 수표 을 할 이 없다__truediv__의 상실이 이유다이러한 "기대된 행동"의 상실은 당신이 (보통) 마술적인 방법을 직접 사용해서는 안 되는 주된 이유다.

두 개의 점이 함께 있으면 처음에는 좀 어색할 수 있다.

f = 1..__truediv__ # or 1..__div__ for python 2

그러나 그것은 다음과 같은 글을 쓰는 것과 같다.

f = 1.0.__truediv__ # or 1.0.__div__ for python 2

왜냐하면float리터럴은 다음과 같은 세 가지 형태로 쓸 수 있다.

normal_float = 1.0
short_float = 1.  # == 1.0
prefixed_float = .1  # == 0.1

뭐가f = 1..__truediv__?

f1의 값을 가진 플로트의 바인딩된 특수 방법이다.구체적으로 말하자면

1.0 / x

Python 3에서 다음을 호출한다.

(1.0).__truediv__(x)

증거:

class Float(float):
    def __truediv__(self, other):
        print('__truediv__ called')
        return super(Float, self).__truediv__(other)

및:

>>> one = Float(1)
>>> one/2
__truediv__ called
0.5

다음 작업을 수행하는 경우:

f = one.__truediv__

우리는 그 바인딩된 방법에 대한 이름을 가지고 있다.

>>> f(2)
__truediv__ called
0.5
>>> f(3)
__truediv__ called
0.3333333333333333

만약 우리가 그 점묘법을 빠듯하게 반복한다면, 이것은 시간을 조금 절약할 수 있을 것이다.

AST(추상 구문 트리) 구문 분석

우리는 AST를 그 표현에 대해 구문 분석하는 것은 우리가 그 표현을 얻고 있다는 것을 말해준다는 것을 알 수 있다.__truediv__속성은, 부동 수긍의 속성,1.0:

>>> import ast
>>> ast.dump(ast.parse('1..__truediv__').body[0])
"Expr(value=Attribute(value=Num(n=1.0), attr='__truediv__', ctx=Load()))"

다음과 같은 결과 기능을 사용할 수 있다.

f = float(1).__truediv__

아니면

f = (1.0).__truediv__

공제

우리는 또한 추론을 통해 그곳에 도달할 수 있다.

그것을 쌓자.

1은 그 자체로int:

>>> 1
1
>>> type(1)
<type 'int'>

1이 플로트된 후 마침표가 있는 경우:

>>> 1.
1.0
>>> type(1.)
<type 'float'>

다음 점 자체는 구문 오류일 수 있지만 플로트의 인스턴스(instance)에서 점 조회를 시작한다.

>>> 1..__truediv__
<method-wrapper '__truediv__' of float object at 0x0D1C7BF0>

아무도 이것에 대해 언급하지 않았다 - 이것은 이제 플로트에서 "바운드 방식"이다.1.0:

>>> f = 1..__truediv__
>>> f
<method-wrapper '__truediv__' of float object at 0x127F3CD8>
>>> f(2)
0.5
>>> f(3)
0.33333333333333331

우리는 같은 기능을 훨씬 더 읽기 쉽게 수행할 수 있었다.

>>> def divide_one_by(x):
...     return 1.0/x
...     
>>> divide_one_by(2)
0.5
>>> divide_one_by(3)
0.33333333333333331

퍼포먼스

.divide_one_by함수는 다른 Python 스택 프레임을 요구하여 바운드 방법보다 다소 느리게 만드는 것이다.

>>> def f_1():
...     for x in range(1, 11):
...         f(x)
...         
>>> def f_2():
...     for x in range(1, 11):
...         divide_one_by(x)
...         
>>> timeit.repeat(f_1)
[2.5495760687176485, 2.5585621018805469, 2.5411816588331888]
>>> timeit.repeat(f_2)
[3.479687248616699, 3.46196088706062, 3.473726342237768]

물론, 만약 여러분이 평범한 리터럴을 사용할 수 있다면, 그것은 훨씬 더 빠르다.

>>> def f_3():
...     for x in range(1, 11):
...         1.0/x
...         
>>> timeit.repeat(f_3)
[2.1224895628296281, 2.1219930218637728, 2.1280188256941983]

참조URL: https://stackoverflow.com/questions/43487811/what-is-1-truediv-does-python-have-a-dot-dot-notation-syntax

반응형