`1 ..__ truediv__` क्या है? क्या पायथन में एक .. ("डॉट डॉट") संकेतन सिंटैक्स है?


190

मैं हाल ही में एक सिंटैक्स में आया था, जिसे मैंने पहले कभी नहीं देखा था जब मैंने अजगर को सीखा था और न ही अधिकांश ट्यूटोरियल में .., यह इस तरह दिखता है:

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

लेकिन मेरे सवाल हैं:

  • यह कैसे कर सकता है?
  • दो बिंदुओं के साथ वास्तव में इसका क्या मतलब है?
  • आप इसे अधिक जटिल कथन (यदि संभव हो) में कैसे उपयोग कर सकते हैं?

यह शायद मुझे भविष्य में कोड की कई लाइनें बचाएगा ... :)


14
नोट: (1).__truediv__वास्तव 1..__truediv__में पूर्व कॉल के रूप में के रूप में ही नहीं है , int.__truediv__जबकि बाद में करता है float.__truediv__। वैकल्पिक रूप से, आप 1 .__truediv__(एक स्थान के साथ) `
Tobias_k

7
ध्यान दें कि 1//8है 0नहीं, 0.125, अजगर के किसी भी प्रकार में।
mkrieger1

1
मुझे याद दिलाता हैif (x <- 3) {...}
दुनो

7
यहां इसका एक उदाहरण उपयोग में है।
ओलिव

3
@KeithC उच्च गुणवत्ता के उत्तर और टिप्पणियाँ नमूना कोड को समझने के लिए अंतर्दृष्टि की आवश्यकता है, कई के लिए आश्चर्य की बात है, विकल्प हैं जो स्पष्ट, अधिक सामान्य और कम से कम कुशल हैं। मेरी मुख्य पकड़ यह है कि पठनीयता मायने रखती है। चतुरता को बचाएं जहां इसकी सबसे अधिक आवश्यकता है - मनुष्यों के साथ संवाद करना।
पीटर वुड

जवाबों:


212

आपके पास floatअनुगामी शून्य के बिना एक शाब्दिक है, जिसे आप तब की __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 उपज देता है।


165
तो जो हमने पाया वह एक देवता है जिसने थोड़ी संक्षिप्तता के लिए बहुत कुछ त्याग दिया और यहाँ हम हैं।
टेम्पोरलवुल्फ़

11
हो सकता है कि कोई व्यक्ति अपने स्रोत कोड को 5.5 "फ्लॉपी डिस्क पर सहेज रहा हो?
थॉमस अय्यूब

10
@ThomasAyoub यह 5.25 होगा "iirc ;-)
jjmontes


2
मजेदार तथ्य, आप इसे जावास्क्रिप्ट में भी कर सकते हैं:1..toString()
डेरेक 會

74

प्रश्न पहले से ही पर्याप्त रूप से उत्तर दिया गया है (यानी @Paul रूनी का उत्तर) लेकिन इन उत्तरों की शुद्धता को सत्यापित करना भी संभव है।

मुझे मौजूदा उत्तरों को फिर से लिखना है: ..एक भी वाक्यविन्यास तत्व नहीं है!

आप यह देख सकते हैं कि स्रोत कोड "टोकन" कैसे है । ये टोकन दर्शाते हैं कि कोड की व्याख्या कैसे की जाती है:

>>> 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.को संख्या के रूप में व्याख्या की जाती है, दूसरा .एक ओपी (एक ऑपरेटर है, इस मामले में "विशेषता प्राप्त करें" ऑपरेटर) और __truediv__विधि नाम है। तो यह सिर्फ __truediv__फ्लोट के तरीके को एक्सेस कर रहा है 1.0

उत्पन्न बायोटेक को देखने का एक अन्य तरीका इसे इकट्ठा करना है। यह वास्तव में उन निर्देशों को दिखाता है जो कुछ कोड निष्पादित होने पर किए जाते हैं: dis

>>> 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भी अजगर के डेटा मॉडल ( 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__सीधे काम करते हैं तो आपके पास ये कमियां नहीं होती हैं। "अपेक्षित व्यवहार" का यह नुकसान मुख्य कारण है कि आप (सामान्य रूप से) सीधे जादू के तरीकों का उपयोग न करें।


40

एक साथ दो बिंदु पहले थोड़ा अजीब हो सकते हैं:

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

यह आश्चर्य की बात है, क्यों इन वैध वाक्यविन्यास हैं, लेकिन 1.__truediv__नहीं है?
एलेक्स हॉल

3
देखें @AlexHall यहाँ.संख्या के भाग के रूप में पार्स किया जा रहा है, और फिर .विधि एक्सेसर के लिए याद आ रही है।
तोबियास_कॉं

7
लेकिन चूंकि यह अजीब और अस्पष्ट वाक्य रचना है, इसलिए शायद इसे टाला जाना चाहिए।
DrMcCleod

11

क्या है f = 1..__truediv__?

fएक मान के साथ एक फ्लोट पर एक बाध्य विशेष विधि है। विशेष रूप से,

1.0 / x

पायथन 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

यदि हम एक तंग पाश में उस बिंदीदार खोज कर रहे थे, तो यह थोड़ा समय बचा सकता है।

सार सिंटेक्स ट्री (एएसटी) को पार्स करना

हम देख सकते हैं कि अभिव्यक्ति के लिए एएसटी को पार्स करना हमें बताता है कि हमें __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'>

अगली बिंदी अपने आप में एक वाक्य रचना होगी, लेकिन यह फ्लोट के उदाहरण पर एक बिंदीदार खोज शुरू करती है:

>>> 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फ़ंक्शन का नकारात्मक पक्ष यह है कि इसके लिए एक और पायथन स्टैक फ्रेम की आवश्यकता होती है, जिससे यह बाध्य विधि की तुलना में कुछ धीमा हो जाता है:

>>> 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]
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.