-> có nghĩa là gì trong định nghĩa hàm Python?


476

Gần đây tôi đã nhận thấy một điều thú vị khi xem đặc tả ngữ pháp Python 3.3 :

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

Khối 'mũi tên' tùy chọn không có trong Python 2 và tôi không thể tìm thấy bất kỳ thông tin nào liên quan đến ý nghĩa của nó trong Python 3. Hóa ra đây là Python chính xác và nó được trình thông dịch chấp nhận:

def f(x) -> 123:
    return x

Tôi nghĩ rằng đây có thể là một loại cú pháp tiền điều kiện, nhưng:

  • Tôi không thể kiểm tra xở đây, tại nó vẫn chưa được xác định,
  • Bất kể tôi đặt gì sau mũi tên (ví dụ 2 < 1), nó không ảnh hưởng đến hành vi chức năng.

Bất cứ ai có thể quen với cú pháp này giải thích nó?

Câu trả lời:


375

Đó là một chú thích chức năng .

Chi tiết hơn, Python 2.x có các tài liệu, cho phép bạn đính kèm một chuỗi siêu dữ liệu vào các loại đối tượng khác nhau. Điều này rất tiện dụng, vì vậy Python 3 mở rộng tính năng bằng cách cho phép bạn đính kèm siêu dữ liệu vào các hàm mô tả các tham số và trả về giá trị của chúng.

Không có trường hợp sử dụng định trước, nhưng PEP gợi ý một số trường hợp. Một cách rất tiện dụng là cho phép bạn chú thích các tham số với các loại dự kiến ​​của chúng; sau đó sẽ dễ dàng viết một trình trang trí xác minh các chú thích hoặc ép buộc các đối số theo đúng loại. Một cách khác là cho phép tài liệu dành riêng cho tham số thay vì mã hóa nó thành chuỗi.


122
Và thông tin có sẵn như là một .__annotations__thuộc tính.
Martijn Pieters

8
Ồ, tôi đã bỏ lỡ một phạm vi kiến ​​thức khá rộng - không chỉ trả về các chú thích giá trị, mà cả các chú thích tham số. Cảm ơn rât nhiều :).
Krippi

4
@Kr Bông Không thể đổ lỗi cho bạn vì đã bỏ lỡ nó, thực tế nó không được sử dụng. Tôi chỉ từng gặp một thư viện sử dụng chúng và nó khá tối nghĩa.

5
__annotations__thuộc tính là một từ điển. Khóa returnnày là khóa được sử dụng để lấy giá trị sau mũi tên.
Keith

9
@delnan - có lẽ lý do mà hầu hết không được sử dụng là vì hầu hết các thư viện python vẫn nhắm đến khả năng tương thích với python2.x. Khi python3.x bắt đầu trở nên chuẩn hơn, chúng ta có thể thấy nhiều thứ hơn xuất hiện ở đây và ở đó ...
mgilson

252

Đây là các chú thích chức năng được đề cập trong PEP 3107 . Cụ thể, ->đánh dấu các chú thích chức năng trở lại.

Ví dụ:

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

Chú thích là từ điển, vì vậy bạn có thể làm điều này:

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

Bạn cũng có thể có cấu trúc dữ liệu python chứ không chỉ là một chuỗi:

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

Hoặc, bạn có thể sử dụng các thuộc tính hàm để xác thực các giá trị được gọi:

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)

Bản in

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

Như các câu trả lời khác đã nêu, ->biểu tượng được sử dụng như một phần của chú thích chức năng. >= 3.5Tuy nhiên, trong các phiên bản gần đây hơn của Python , nó có nghĩa được xác định .

PEP 3107 - Chú thích chức năng mô tả đặc điểm kỹ thuật, xác định các thay đổi ngữ pháp, sự tồn tại của func.__annotations__chúng được lưu trữ và thực tế là trường hợp sử dụng vẫn còn mở.

Trong Python 3.5, PEP 484 - Gợi ý loại gắn một ý nghĩa duy nhất cho điều này: ->được sử dụng để chỉ ra loại mà hàm trả về. Có vẻ như điều này sẽ được thi hành trong các phiên bản trong tương lai như được mô tả trong phần Sử dụng các chú thích hiện có :

Lược đồ có thể hiểu nhanh nhất sẽ đưa ra sự phản đối thầm lặng của các chú thích không gợi ý kiểu trong 3.6, khấu hao hoàn toàn trong 3.7 và khai báo các gợi ý kiểu như là chỉ sử dụng các chú thích trong Python 3.8.

(Nhấn mạnh của tôi)

Điều này đã không thực sự được thực hiện theo 3.6như tôi có thể nói để nó có thể bị va chạm với các phiên bản trong tương lai.

Theo đó, ví dụ bạn đã cung cấp:

def f(x) -> 123:
    return x

sẽ bị cấm trong tương lai (và trong các phiên bản hiện tại sẽ gây nhầm lẫn), cần phải đổi thành:

def f(x) -> int:
    return x

để nó mô tả hiệu quả hàm đó ftrả về một đối tượng kiểu int.

Các chú thích không được sử dụng theo bất kỳ cách nào bởi chính Python, nó khá nhiều dân cư và bỏ qua chúng. Đó là thư viện của bên thứ 3 để làm việc với họ.


64

Trong đoạn mã sau:

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

các -> intchỉ nói rằng f()trả về một số nguyên (nhưng nó không buộc các hàm trả về một số nguyên). Nó được gọi là một chú thích trở lại , và có thể được truy cập như f.__annotations__['return'].

Python cũng hỗ trợ các chú thích tham số:

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

: floatnói với những người đọc chương trình (và một số thư viện / chương trình của bên thứ ba, ví dụ như pylint) xnên là a float. Nó được truy cập như f.__annotations__['x'], và không có bất kỳ ý nghĩa của chính nó. Xem tài liệu để cho biết thêm thông tin chi tiết:

https://docs.python.org/3/reference/compound_stmts.html#feft-def địnhs https://www.python.org/dev/peps/pep-3107/


4

Điều này có nghĩa là loại kết quả mà hàm trả về, nhưng nó có thể None.

Nó phổ biến rộng rãi trong các thư viện hiện đại được định hướng trên Python 3.x.

Ví dụ, nó có mã của hồ sơ gấu trúc thư viện ở nhiều nơi chẳng hạn:

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.

"Điều này có nghĩa là loại kết quả mà hàm trả về, nhưng nó có thể là Không có." Nó có thể là Không hoặc bất kỳ loại nào khác.
Ebram Shehata

2

def function(arg)->123:

Nó chỉ đơn giản là một kiểu trả về, số nguyên trong trường hợp này không quan trọng bạn viết số nào.

như Java :

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

Nhưng đối với Python (cách Jim Fasarakis Hilliard nói) , kiểu trả về chỉ là một gợi ý , vì vậy nó gợi ý trả về nhưng dù sao cũng cho phép trả về loại khác như một chuỗi ..


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

Bản tóm tắt của tôi:

  1. Đơn giản ->là được giới thiệu để khiến các nhà phát triển tùy ý chỉ định kiểu trả về của hàm. Xem Đề xuất cải tiến Python 3107

  2. Đây là một dấu hiệu cho thấy mọi thứ có thể phát triển như thế nào trong tương lai khi Python được áp dụng rộng rãi - một dấu hiệu cho việc gõ mạnh - đây là quan sát cá nhân của tôi.

  3. Bạn có thể chỉ định các loại cho các đối số là tốt. Chỉ định kiểu trả về của các hàm và đối số sẽ giúp giảm lỗi logic và cải thiện mã cải tiến.

  4. Bạn có thể có các biểu thức dưới dạng kiểu trả về (cho cả ở cấp độ hàm và tham số) và kết quả của các biểu thức có thể được truy cập thông qua thuộc tính 'return' của đối tượng chú thích . các chú thích sẽ trống cho giá trị biểu thức / trả về cho các hàm nội tuyến lambda.


Cảm ơn bạn đã sửa chữa.
maz
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.