-> หมายถึงอะไรในนิยามฟังก์ชันของ Python


476

ฉันเพิ่งสังเกตเห็นสิ่งที่น่าสนใจเมื่อดูข้อมูลจำเพาะของไวยากรณ์ Python 3.3 :

funcdef: 'def' NAME parameters ['->' test] ':' suite

บล็อก 'ลูกศร' ไม่ปรากฏใน Python 2 และฉันไม่พบข้อมูลใด ๆ เกี่ยวกับความหมายของมันใน Python 3 ปรากฎว่านี่เป็น Python ที่ถูกต้องและเป็นที่ยอมรับโดยล่าม:

def f(x) -> 123:
    return x

ฉันคิดว่านี่อาจเป็นรูปแบบของเงื่อนไขเบื้องต้น แต่:

  • ฉันไม่สามารถทดสอบได้xที่นี่เพราะมันยังไม่ได้กำหนด
  • ไม่ว่าฉันจะวางลูกศรไว้ที่ใด (เช่น2 < 1) มันไม่ส่งผลกระทบต่อการทำงานของฟังก์ชัน

ใครบ้างที่คุ้นเคยกับไวยากรณ์นี้จะอธิบายหรือไม่

คำตอบ:


375

มันเป็นคำอธิบายประกอบฟังก์ชั่น

ในรายละเอียดเพิ่มเติม Python 2.x มีเอกสารซึ่งอนุญาตให้คุณแนบสตริงข้อมูลเมตากับวัตถุประเภทต่างๆ สิ่งนี้มีประโยชน์อย่างน่าอัศจรรย์ดังนั้น Python 3 จึงขยายคุณสมบัติโดยให้คุณแนบข้อมูลเมตากับฟังก์ชันที่อธิบายพารามิเตอร์และค่าส่งคืน

ไม่มีกรณีการใช้งานล่วงหน้า แต่ PEP แนะนำให้ใช้หลายกรณี หนึ่งที่มีประโยชน์มากคือการอนุญาตให้คุณใส่คำอธิบายประกอบพารามิเตอร์ตามประเภทที่คาดไว้ มันจะง่ายต่อการเขียนมัณฑนากรที่ตรวจสอบบันทึกย่อหรือ coerces อาร์กิวเมนต์ประเภทที่ถูกต้อง อีกประการหนึ่งคือการอนุญาตให้เอกสารเฉพาะพารามิเตอร์แทนการเข้ารหัสลงใน docstring


122
และข้อมูลที่มีอยู่เป็น.__annotations__คุณลักษณะ
Martijn Pieters

8
ว้าวฉันไม่ได้รับความรู้อย่างกว้างขวาง - ไม่เพียง แต่จะส่งคืนหมายเหตุประกอบมูลค่า แต่ยังมีคำอธิบายประกอบพารามิเตอร์ ขอบคุณมาก :).
Krotton

4
@Krotton ไม่สามารถตำหนิคุณสำหรับการหายไปมันไม่ได้ใช้จริง ฉันเคยพบห้องสมุดเดียวที่ใช้มันและมันค่อนข้างคลุมเครือ

5
และ__annotations__คุณลักษณะเป็นพจนานุกรม กุญแจสำคัญreturnคือกุญแจที่ใช้เรียกค่าหลังจากลูกศร
Keith

9
@delnan - อาจเป็นสาเหตุที่ส่วนใหญ่ไม่ได้ใช้เพราะห้องสมุดไพ ธ อนส่วนใหญ่ยังคงมุ่งมั่นที่จะเข้ากันได้กับ python2.x เมื่อ python3.x เริ่มเป็นมาตรฐานมากขึ้นเราอาจเห็นสิ่งเหล่านี้โผล่ขึ้นมาที่นี่และที่นั่น ...
mgilson

252

เหล่านี้เป็นคำอธิบายประกอบฟังก์ชั่นที่ครอบคลุมในPEP 3107 โดยเฉพาะ->เครื่องหมายคำอธิบายประกอบตอบแทนการทำงาน

ตัวอย่าง:

>>> def kinetic_energy(m:'in KG', v:'in M/S')->'Joules': 
...    return 1/2*m*v**2
... 
>>> kinetic_energy.__annotations__
{'return': 'Joules', 'v': 'in M/S', 'm': 'in KG'}

คำอธิบายประกอบเป็นพจนานุกรมดังนั้นคุณสามารถทำสิ่งนี้ได้:

>>> '{:,} {}'.format(kinetic_energy(20,3000),
      kinetic_energy.__annotations__['return'])
'90,000,000.0 Joules'

คุณสามารถมีโครงสร้างข้อมูลหลามมากกว่าเพียงแค่สตริง:

>>> rd={'type':float,'units':'Joules','docstring':'Given mass and velocity returns kinetic energy in Joules'}
>>> def f()->rd:
...    pass
>>> f.__annotations__['return']['type']
<class 'float'>
>>> f.__annotations__['return']['units']
'Joules'
>>> f.__annotations__['return']['docstring']
'Given mass and velocity returns kinetic energy in Joules'

หรือคุณสามารถใช้ฟังก์ชั่นฟังก์ชั่นเพื่อตรวจสอบค่าที่เรียกว่า:

def validate(func, locals):
    for var, test in func.__annotations__.items():
        value = locals[var]
        try: 
            pr=test.__name__+': '+test.__docstring__
        except AttributeError:
            pr=test.__name__   
        msg = '{}=={}; Test: {}'.format(var, value, pr)
        assert test(value), msg

def between(lo, hi):
    def _between(x):
            return lo <= x <= hi
    _between.__docstring__='must be between {} and {}'.format(lo,hi)       
    return _between

def f(x: between(3,10), y:lambda _y: isinstance(_y,int)):
    validate(f, locals())
    print(x,y)

พิมพ์

>>> f(2,2) 
AssertionError: x==2; Test: _between: must be between 3 and 10
>>> f(3,2.1)
AssertionError: y==2.1; Test: <lambda>

86

ตามที่คำตอบอื่น ๆ ได้ระบุไว้->สัญลักษณ์จะถูกใช้เป็นส่วนหนึ่งของคำอธิบายประกอบของฟังก์ชัน >= 3.5แม้ว่าใน Python เวอร์ชันล่าสุดจะมีความหมายที่กำหนดไว้

PEP 3107 - คำอธิบายประกอบฟังก์ชั่นอธิบายข้อมูลจำเพาะกำหนดการเปลี่ยนแปลงไวยากรณ์การดำรงอยู่ของfunc.__annotations__สิ่งที่พวกเขาจะถูกเก็บไว้และความจริงที่ว่ามันใช้กรณียังคงเปิดอยู่

ใน Python 3.5นั้นPEP 484 - Type Hintsแนบความหมายเดียวกับสิ่งนี้: ->ใช้เพื่อระบุประเภทที่ฟังก์ชันส่งคืน ดูเหมือนว่าจะมีการบังคับใช้ในเวอร์ชันในอนาคตตามที่อธิบายไว้ในสิ่งที่เกี่ยวกับการใช้คำอธิบายประกอบที่มีอยู่ :

รูปแบบที่เป็นไปได้ที่เร็วที่สุดจะแนะนำการลดทอนอย่างเงียบ ๆ ของคำอธิบายประกอบแบบ non-type-hint ใน 3.6, การคัดค้านแบบเต็มใน 3.7 และประกาศคำใบ้ประเภทเป็นการอนุญาตให้ใช้คำอธิบายประกอบใน Python 3.8 เท่านั้น

(เน้นเหมือง)

สิ่งนี้ไม่ได้ถูกนำไปใช้จริง3.6เท่าที่ฉันสามารถบอกได้ดังนั้นมันอาจชนกับเวอร์ชันในอนาคต

จากตัวอย่างนี้คุณได้ระบุ:

def f(x) -> 123:
    return x

จะถูกห้ามในอนาคต (และในเวอร์ชันปัจจุบันจะสับสน) มันจะต้องเปลี่ยนเป็น:

def f(x) -> int:
    return x

ให้มันได้อย่างมีประสิทธิภาพอธิบายฟังก์ชั่นที่ให้ผลตอบแทนวัตถุของการพิมพ์fint

คำอธิบายประกอบไม่ได้ถูกใช้ในทางใดทางหนึ่งโดย Python เอง แต่ก็มีประชากรค่อนข้างมากและไม่สนใจมัน มันขึ้นอยู่กับห้องสมุดบุคคลที่สามที่จะทำงานกับพวกเขา


64

ในรหัสต่อไปนี้:

def f(x) -> int:
    return int(x)

-> intเพียงแค่บอกว่าf()ผลตอบแทนที่เป็นจำนวนเต็ม ( แต่ก็ไม่ได้บังคับให้ฟังก์ชั่นที่จะกลับมาเป็นจำนวนเต็ม) มันจะเรียกว่าเป็นคำอธิบายประกอบการกลับมาf.__annotations__['return']และสามารถเข้าถึงได้เป็น

Python ยังรองรับหมายเหตุประกอบพารามิเตอร์:

def f(x: float) -> int:
    return int(x)

: floatบอกคนที่อ่านโปรแกรม (และบางห้องสมุดของบุคคลที่สาม / โปรแกรมเช่น pylint) ที่ควรจะเป็นx floatมันเข้าถึงได้f.__annotations__['x']และไม่มีความหมายใด ๆ ด้วยตัวเอง ดูเอกสารประกอบสำหรับข้อมูลเพิ่มเติม:

https://docs.python.org/3/reference/compound_stmts.html#function-definitions https://www.python.org/dev/peps/pep-3107/


4

นี่หมายถึงประเภทของผลลัพธ์ที่ฟังก์ชันส่งคืน แต่อาจเป็นNoneได้

มันแพร่หลายในห้องสมุดสมัยใหม่ที่เน้น Python 3.x

ตัวอย่างเช่นมันมีอยู่ในรหัสของห้องสมุดทำแพนด้า - โปรไฟล์ในหลายสถานที่เช่น:

def get_description(self) -> dict:

def get_rejected_variables(self, threshold: float = 0.9) -> list:

def to_file(self, output_file: Path or str, silent: bool = True) -> None:
"""Write the report to a file.

"นี่หมายถึงประเภทของผลลัพธ์ที่ฟังก์ชันส่งคืน แต่อาจเป็น None" สามารถเป็น None หรือชนิดอื่นใดก็ได้
Ebram Shehata

2

def function(arg)->123:

มันเป็นเพียงประเภทผลตอบแทนจำนวนเต็มในกรณีนี้ไม่สำคัญว่าคุณจะเขียนหมายเลขใด

ชอบJava :

public int function(int args){...}

แต่สำหรับงูหลาม ( จิมฟาซารากิสฮิลลาร์ดพูดว่า) ประเภทผลตอบแทนมันเป็นเพียงคำใบ้ดังนั้นจึงแนะนำให้กลับ แต่อนุญาตให้กลับชนิดอื่นเช่นสตริงได้ ..


1
def f(x) -> 123:
    return x

สรุปของฉัน:

  1. ->มีการแนะนำเพียงเพื่อให้นักพัฒนาเลือกระบุประเภทการคืนของฟังก์ชัน ดูข้อเสนอการปรับปรุง Python 3107

  2. นี่เป็นข้อบ่งชี้ว่าสิ่งต่าง ๆ อาจพัฒนาในอนาคตอย่างไรเนื่องจาก Python ถูกนำไปใช้อย่างกว้างขวาง - เป็นสิ่งบ่งชี้ถึงการพิมพ์ที่แข็งแกร่ง - นี่คือการสังเกตส่วนตัวของฉัน

  3. คุณสามารถระบุประเภทของอาร์กิวเมนต์ได้เช่นกัน การระบุชนิดส่งคืนของฟังก์ชันและอาร์กิวเมนต์จะช่วยในการลดข้อผิดพลาดเชิงตรรกะและปรับปรุงการปรับปรุงรหัส

  4. คุณสามารถมีนิพจน์เป็นชนิดส่งคืน (สำหรับทั้งที่ฟังก์ชันและระดับพารามิเตอร์) และผลลัพธ์ของนิพจน์สามารถเข้าถึงได้ผ่านแอททริบิวต์ 'return' ของคำอธิบายประกอบ หมายเหตุประกอบจะว่างเปล่าสำหรับค่า expression / return สำหรับฟังก์ชัน inline lambda


ขอบคุณสำหรับการแก้ไข
maz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.