Apa -> artinya dalam definisi fungsi Python?

476

Saya baru-baru ini memperhatikan sesuatu yang menarik ketika melihat spesifikasi tata bahasa Python 3.3 :

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

Blok 'panah' opsional tidak ada di Python 2 dan saya tidak dapat menemukan informasi mengenai artinya dalam Python 3. Ternyata ini adalah Python yang benar dan diterima oleh juru bahasa:

def f(x) -> 123:
    return x

Saya berpikir bahwa ini mungkin semacam sintaksis prasyarat, tetapi:

  • Saya tidak dapat menguji di xsini, karena masih belum ditentukan,
  • Tidak peduli apa yang saya masukkan setelah panah (misalnya 2 < 1), itu tidak mempengaruhi perilaku fungsi.

Adakah yang bisa terbiasa dengan sintaks ini menjelaskannya?

Krotton
sumber

Jawaban:

375

Ini adalah anotasi fungsi .

Secara lebih rinci, Python 2.x memiliki dokumen, yang memungkinkan Anda untuk melampirkan string metadata ke berbagai jenis objek. Ini sangat berguna, jadi Python 3 memperluas fitur dengan memungkinkan Anda untuk melampirkan metadata ke fungsi yang menggambarkan parameter mereka dan mengembalikan nilai.

Tidak ada kasus penggunaan yang terbentuk sebelumnya, tetapi PEP menyarankan beberapa. Salah satu yang sangat berguna adalah memungkinkan Anda untuk membubuhi keterangan parameter dengan tipe yang diharapkan; maka akan mudah untuk menulis dekorator yang memverifikasi penjelasan atau memaksa argumen ke jenis yang tepat. Cara lain adalah dengan mengizinkan dokumentasi spesifik parameter alih-alih menyandikannya ke dalam docstring.

Katriel
sumber
122
Dan informasi tersedia sebagai .__annotations__atribut.
Martijn Pieters
8
Wow, saya melewatkan bidang pengetahuan yang cukup luas - tidak hanya mengembalikan anotasi nilai, tetapi juga anotasi parameter. Terima kasih banyak :).
Krotton
4
@Krotton Tidak dapat menyalahkan Anda karena melewatkannya, ini praktis tidak digunakan. Saya hanya pernah bertemu satu perpustakaan menggunakan mereka, dan itu cukup jelas.
5
Dan __annotations__atributnya adalah kamus. Kuncinya returnadalah yang digunakan untuk mengambil nilai setelah panah.
Keith
9
@delnan - mungkin alasan bahwa sebagian besar tidak digunakan adalah karena sebagian besar pustaka python masih bertujuan untuk kompatibel dengan python2.x. Ketika python3.x mulai menjadi lebih standar, kita mungkin melihat lebih banyak hal ini bermunculan di sana-sini ...
mgilson
252

Ini adalah penjelasan fungsi yang tercakup dalam PEP 3107 . Secara khusus, ->menandai anotasi fungsi pengembalian.

Contoh:

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

Anotasi adalah kamus, sehingga Anda dapat melakukan ini:

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

Anda juga dapat memiliki struktur data python daripada hanya string:

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

Atau, Anda bisa menggunakan atribut fungsi untuk memvalidasi nilai yang disebut:

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)

Cetakan

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

Seperti jawaban lain telah menyatakan, ->simbol digunakan sebagai bagian dari penjelasan fungsi. Namun, dalam versi Python yang lebih baru >= 3.5, ia memiliki makna yang jelas .

PEP 3107 - Anotasi Fungsi mendeskripsikan spesifikasi, mendefinisikan perubahan tata bahasa, keberadaan func.__annotations__penyimpanannya, dan fakta bahwa use case-nya masih terbuka.

Dalam Python 3.5, PEP 484 - Type Hints melampirkan arti tunggal untuk ini: ->digunakan untuk menunjukkan jenis fungsi yang dikembalikan. Sepertinya ini juga akan diberlakukan di versi mendatang seperti yang dijelaskan dalam Bagaimana dengan penggunaan anotasi yang ada :

Skema yang paling cepat dibayangkan akan memperkenalkan penghentian diam-diam dari anotasi non- tip -petunjuk di 3.6, penghentian penuh pada 3.7, dan menyatakan petunjuk tipe sebagai satu-satunya penggunaan anotasi yang diizinkan dalam Python 3.8.

(Penekanan milikku)

Ini belum benar-benar dilaksanakan 3.6sejauh yang saya tahu sehingga mungkin akan terbentur ke versi masa depan.

Menurut ini, contoh yang Anda berikan:

def f(x) -> 123:
    return x

akan dilarang di masa mendatang (dan dalam versi saat ini akan membingungkan), itu perlu diubah menjadi:

def f(x) -> int:
    return x

untuk itu secara efektif menggambarkan fungsi yang fmengembalikan objek bertipe int.

Anotasi tidak digunakan dengan cara apa pun oleh Python sendiri, cukup banyak mengisi dan mengabaikannya. Terserah perpustakaan pihak ketiga untuk bekerja dengannya.

Dimitris Fasarakis Hilliard
sumber
64

Dalam kode berikut:

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

yang -> inthanya mengatakan bahwa f()mengembalikan integer (tetapi tidak memaksa fungsi untuk mengembalikan integer). Ini disebut anotasi pengembalian , dan dapat diakses sebagai f.__annotations__['return'].

Python juga mendukung anotasi parameter:

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

: floatmemberi tahu orang yang membaca program (dan beberapa perpustakaan / program pihak ketiga, misalnya pylint) yang xseharusnya a float. Ini diakses sebagai f.__annotations__['x'], dan tidak memiliki arti apa pun dengan sendirinya. Lihat dokumentasi untuk informasi lebih lanjut:

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

MaxiMouse
sumber
4

Ini berarti jenis hasil fungsi yang dikembalikan, tetapi bisa juga None.

Ini tersebar luas di perpustakaan modern yang berorientasi pada Python 3.x.

Misalnya, ada dalam kode panda-profiling profil di banyak tempat misalnya:

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.
Vitalii
sumber
"Ini berarti jenis hasil fungsi yang dikembalikan, tetapi bisa berupa Tidak Ada." Itu bisa berupa Tidak Ada atau tipe lainnya.
Ebram Shehata
2

def function(arg)->123:

Ini hanya tipe pengembalian, integer dalam hal ini tidak masalah nomor yang Anda tulis.

seperti Java :

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

Tapi untuk Python (bagaimana Jim Fasarakis Hilliard berkata) tipe kembali itu hanya petunjuk , jadi itu menyarankan pengembalian tetapi tetap mengizinkan untuk mengembalikan tipe lain seperti string ..

Mike D3ViD Tyson
sumber
1
def f(x) -> 123:
    return x

Ringkasan saya:

  1. Secara sederhana ->diperkenalkan untuk membuat pengembang menentukan secara spesifik jenis pengembalian fungsi. Lihat Proposal Peningkatan Python 3107

  2. Ini adalah indikasi tentang bagaimana hal-hal dapat berkembang di masa depan karena Python diadopsi secara luas - indikasi ke arah pengetikan yang kuat - ini adalah pengamatan pribadi saya.

  3. Anda dapat menentukan jenis argumen juga. Menentukan tipe pengembalian fungsi dan argumen akan membantu mengurangi kesalahan logis dan meningkatkan peningkatan kode.

  4. Anda dapat memiliki ekspresi sebagai tipe kembali (baik pada fungsi dan tingkat parameter) dan hasil dari ekspresi dapat diakses melalui atribut 'kembali' objek penjelasan . anotasi akan kosong untuk nilai ekspresi / pengembalian untuk fungsi inline lambda.

maz
sumber
Terima kasih atas koreksi.
maz