Hướng dẫn python docstring vs type hints - python docstring so với gợi ý về loại

TL; DR: Sử dụng chú thích loại, chúng thật tuyệt vời.

Đối với cả Python và jedi, nó không tạo ra sự khác biệt mà bạn sử dụng tài liệu hoặc chú thích chức năng. Cả hiệu suất và tác động bộ nhớ không nên được chú ý. Rõ ràng có một chi phí thời gian chạy nhỏ trong cả hai trường hợp.

Docstrings chỉ đơn giản được chuyển đổi thành chuỗi Python và được lưu trữ trong thuộc tính function.__doc__. Điều này mất một vài byte bộ nhớ, nhưng bạn không nên quan tâm đến điều đó. Một tài liệu rất lớn gồm 1000 ký tự vẫn chỉ sử dụng RAM 1KB. Nếu bộ nhớ của bạn bị hạn chế, bạn có thể chỉ cần sử dụng python -o để loại bỏ các tài liệu (và cũng khẳng định, hãy tìm nó).

Loại chú thích (PEP 484, ví dụ: def foo(a: int) -> str:) được lưu trữ trong function.__annotations__:

>>> def foo(bar: int): pass
... 
>>> foo.__annotations__
{'bar': }

Những chú thích này rõ ràng cũng sử dụng một số không gian (nhưng thậm chí ít hơn các tài liệu). Tuy nhiên, chúng không có ảnh hưởng đến việc thực hiện thời gian chạy (ngoại trừ nếu bạn chơi rõ ràng với __annotations__.

Tôi sẽ khuyên bạn nên sử dụng các chú thích loại. Chúng đã được giới thiệu, vì phân tích/IDE tĩnh và chắc chắn là tương lai khi nói đến việc ghi lại các loại của bạn. Cũng có rất nhiều công việc hạnh phúc trên mypy, jedi và các công cụ khác để làm cho các chú thích loại có thể sử dụng hơn trong việc xác minh các chương trình. Sử dụng các chú thích loại đã và bạn sẽ sẵn sàng cho tương lai.

Cập nhật lần cuối vào ngày 21 tháng 6 năm 2022

Mã nguồn của một chương trình nên có thể đọc được cho con người. Làm cho nó chạy chính xác chỉ là một nửa mục đích của nó. Nếu không có một mã nhận xét đúng đắn, sẽ rất khó cho một người, bao gồm cả tương lai bạn, để hiểu được lý do và ý định đằng sau mã. Nó cũng sẽ làm cho mã không thể duy trì. Trong Python, có nhiều cách để thêm các mô tả vào mã để làm cho nó dễ đọc hơn hoặc làm cho ý định rõ ràng hơn. Sau đây, chúng ta sẽ thấy cách chúng ta nên sử dụng đúng bình luận, tài liệu và gõ gợi ý để làm cho mã của chúng ta dễ hiểu hơn. Sau khi hoàn thành hướng dẫn này, bạn sẽ biết:

  • Cách sử dụng bình luận thích hợp trong Python là gì
  • Làm thế nào chuỗi theo nghĩa đen hoặc tài liệu có thể thay thế các bình luận trong một số trường hợp
  • Gợi ý loại trong Python là gì và làm thế nào chúng có thể giúp chúng tôi hiểu mã tốt hơn

Bắt đầu dự án của bạn với cuốn sách mới Python for Machine Learning, bao gồm các hướng dẫn từng bước và các tệp mã nguồn Python cho tất cả các ví dụ. with my new book Python for Machine Learning, including step-by-step tutorials and the Python source code files for all examples.

Bắt đầu nào.

Hướng dẫn python docstring vs type hints - python docstring so với gợi ý về loại

Nhận xét, tài liệu và gõ gợi ý trong mã Python. Ảnh của Rhythm Gidel. Một số quyền được bảo lưu

Tổng quan

Hướng dẫn này là trong ba phần, chúng là:

  • Thêm nhận xét vào mã Python
  • Sử dụng Docstrings
  • Sử dụng các gợi ý loại trong mã Python

Hầu như tất cả các ngôn ngữ lập trình đều có cú pháp chuyên dụng cho các bình luận. Nhận xét sẽ bị bỏ qua bởi các trình biên dịch hoặc phiên dịch viên, và do đó chúng không có tác dụng đối với luồng lập trình hoặc logic. Nhưng với ý kiến, dễ đọc mã hơn.

Trong các ngôn ngữ như C ++, chúng ta có thể thêm các bình luận nội tuyến trực tiếp với một dấu gạch chéo kép hàng đầu (//) hoặc thêm các khối nhận xét được đặt bởi & nbsp; ____ ____ 10 & nbsp; và & nbsp; ________ 11. Tuy nhiên, trong Python, chúng tôi chỉ có phiên bản nội tuyến trực tuyến và chúng được giới thiệu bởi nhân vật băm hàng đầu (jedi2).

Nó khá dễ dàng để viết bình luận để giải thích mọi dòng mã, nhưng đó thường là một sự lãng phí. Khi mọi người đọc mã nguồn, các bình luận thường dễ dàng thu hút sự chú ý của họ và do đó đặt quá nhiều bình luận sẽ làm mất tập trung việc đọc. Ví dụ, những điều sau đây là không cần thiết và mất tập trung:

Nhập dữ liệudatetime

Timestamp = datetime.dateTime.now () & nbsp; & nbsp;# Nhận ngày và giờ hiện tại=datetime.datetime.now()  # Get the current date and time

x = 0 & nbsp; & nbsp; & nbsp; & nbsp;# khởi tạo X đến 0=0    # initialize x to zero

Nhận xét như thế này chỉ đơn thuần là lặp lại những gì mã làm. Trừ khi mã bị che khuất, những bình luận này không thêm giá trị cho mã. Ví dụ dưới đây có thể là một trường hợp cận biên trong đó tên là PP PPF (hàm điểm phần trăm) ít được biết đến so với thuật ngữ CDF CDF (hàm phân phối tích lũy):

Nhập Scipy.statsscipy.stats

z_alpha = scipy.stats.norm.ppf (0.975) & nbsp; & nbsp;# gọi cdf nghịch đảo của tiêu chuẩn bình thường=scipy.stats.norm.ppf(0.975)  # Call the inverse CDF of standard normal

Nhận xét tốt nên cho biết lý do tại sao chúng tôi đang làm điều gì đó. Hãy cùng nhìn vào ví dụ sau:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

def adadelta (mục tiêu, phái sinh, giới hạn, n_iter, rho, ep = 1e-3):adadelta(objective,derivative,bounds,n_iter,rho,ep=1e-3):

& nbsp; & nbsp; & nbsp; & nbsp;# tạo một điểm ban đầu# generate an initial point

    solution=bounds[:,0]+rand(len(bounds))*(bounds[:,1]-bounds[:,0])solution =bounds[:,0]+rand(len(bounds))*(bounds[:,1]- bounds[:,0])

& nbsp; & nbsp; & nbsp; & nbsp;# danh sách để giữ các gradient vuông trung bình cho mỗi biến và# lists to hold the average square gradients for each variable and

& nbsp; & nbsp; & nbsp; & nbsp;# Cập nhật tham số trung bình# average parameter updates

    sq_grad_avg=[0.0for_inrange(bounds.shape[0])]sq_grad_avg=[0.0 for_inrange(bounds.shape[0])]

    sq_para_avg=[0.0for_inrange(bounds.shape[0])]sq_para_avg=[0.0for_in range(bounds.shape[0])]

& nbsp; & nbsp; & nbsp; & nbsp;# run the gradient descent

& nbsp; & nbsp; & nbsp; & nbsp; forit inrange (n_iter):forit inrange(n_iter):

        gradient=derivative(solution[0],solution[1])gradient =derivative(solution[0],solution[1])

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# update the moving average of the squared partial derivatives

        foriinrange(gradient.shape[0]):fori inrange(gradient.shape[0]):

            sg=gradient[i]**2.0sg=gradient[i]**2.0

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;sq_grad_avg[i] =(sq_grad_avg[i]*rho)+(sg *(1.0-rho))

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# build a solution one variable at a time

        new_solution=list()new_solution =list()

        foriinrange(solution.shape[0]):foriinrange(solution.shape[0]):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# calculate the step size for this variable

            alpha=(ep+sqrt(sq_para_avg[i]))/(ep+sqrt(sq_grad_avg[i]))alpha=(ep+sqrt(sq_para_avg[i]))/(ep+ sqrt(sq_grad_avg[i]))

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# calculate the change and update the moving average of the squared change

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;change=alpha * gradient[i]

            sq_para_avg[i]=(sq_para_avg[i]*rho)+(change**2.0*(1.0-rho))sq_para_avg[i]=(sq_para_avg[i]*rho)+ (change**2.0*(1.0-rho))

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# calculate the new position in this variable and store as new solution

            value=solution[i]-changevalue =solution[i]-change

            new_solution.append(value)new_solution.append(value)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# đánh giá điểm ứng cử viên# evaluate candidate point

        solution=asarray(new_solution)solution =asarray(new_solution)

        solution_eval=objective(solution[0],solution[1])solution_eval=objective(solution[0],solution[1])

& nbsp;# report progress

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;print('>%d f(%s) = %.5f'%(it,solution,solution_eval))

    return[solution,solution_eval]return[solution, solution_eval]

Hàm trên đang thực hiện thuật toán Adadelta. Trong dòng đầu tiên, khi chúng tôi gán một cái gì đó cho biến jedi3, chúng tôi không viết nhận xét như là một phép nội suy ngẫu nhiên giữa các giới hạn [:, 0] và giới hạn [:, 1] vì đó chỉ là lặp lại mã. Chúng tôi nói rằng ý định của dòng này là để tạo ra một điểm ban đầu. Tương tự, đối với các nhận xét khác trong hàm, chúng tôi đánh dấu một trong những vòng lặp là thuật toán gốc gradient thay vì chỉ nói lặp lại cho một số thời điểm nhất định.

Một vấn đề quan trọng mà chúng tôi muốn nhớ khi viết nhận xét hoặc sửa đổi mã là đảm bảo nhận xét mô tả chính xác mã. Nếu họ mâu thuẫn, nó sẽ gây nhầm lẫn cho độc giả. Vì vậy, chúng ta không nên đặt nhận xét vào dòng đầu tiên của ví dụ trên để đặt giải pháp ban đầu cho phần dưới của LowerBound trong khi mã rõ ràng ngẫu nhiên giải pháp ban đầu hoặc ngược lại. Nếu đây là những gì bạn dự định làm, bạn nên cập nhật nhận xét và mã cùng một lúc.

Một ngoại lệ sẽ là những bình luận của người khác. Thỉnh thoảng, khi chúng tôi có ý tưởng về cách cải thiện mã nhưng chưa thay đổi nó, chúng tôi có thể đưa ra nhận xét để làm về mã. Chúng tôi cũng có thể sử dụng nó để đánh dấu việc triển khai không đầy đủ. Ví dụ,

# TODO Thay thế mã Keras bên dưới bằng TensorFlow

từ keras.models nhập tuần tựkeras.models import Sequential

từ keras.layers nhập Conv2Dkeras.layers import Conv2D

model=Sequential()=Sequential()

model.add(Conv2D(1,(3,3),strides=(2,2),input_shape=(8,8,1))).add(Conv2D(1, (3,3),strides=(2,2),input_shape=(8,8,1)))

model.summary().summary()

.....

Đây là một thông lệ phổ biến và nhiều IDE sẽ làm nổi bật khối bình luận khác nhau khi từ khóa jedi4 được tìm thấy. Tuy nhiên, nó được cho là tạm thời và chúng ta không nên lạm dụng nó như một hệ thống theo dõi vấn đề.

Tóm lại, một số thực tiễn tốt nhất của người Viking về mã nhận xét được liệt kê như sau:

  • Nhận xét không nên khôi phục mã nhưng giải thích nó
  • Nhận xét không nên gây nhầm lẫn nhưng loại bỏ nó
  • Đặt ý kiến ​​về mã không tầm thường để hiểu; Ví dụ: Nêu sử dụng cú pháp đơn phương, đặt tên cho thuật toán đang được sử dụng hoặc giải thích ý định hoặc giả định
  • Nhận xét nên súc tích và đơn giản
  • Giữ một phong cách nhất quán và sử dụng ngôn ngữ trong bình luận
  • Luôn thích có một mã được viết tốt hơn không cần bình luận bổ sung

Sử dụng Docstrings

Trong C ++, chúng ta có thể viết một khối lớn các bình luận như sau:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

TcpSocketBase::~TcpSocketBase(void)::~TcpSocketBase(void)

{

  NS_LOG_FUNCTION(this);NS_LOG_FUNCTION(this);

  m_node=nullptr;m_node=nullptr;

  if(m_endPoint!=nullptr)if (m_endPoint!=nullptr)

    {{

      NS_ASSERT(m_tcp!=nullptr);NS_ASSERT(m_tcp!=nullptr);

      /*/*

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; * Khi ràng buộc, IPv4ENDPOINT được phân bổ và đặt thành m_endpoint và

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; * Phá hủyCallback được đặt thành tcpsocketbase :: phá hủy. Nếu chúng ta gọi

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; * M_TCP-> Deallocate, nó sẽ phá hủy IPv4EndPointDemux :: DealLocate,

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; * Lần lượt phá hủy m_endpoint của tôi và lần lượt gọi

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; * Tcpsocketbase :: phá hủy thành Nullify M_Node, M_EndPoint và M_TCP.

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; */

      NS_ASSERT(m_endPoint!=nullptr);NS_ASSERT(m_endPoint!=nullptr);

      m_tcp->DeAllocate(m_endPoint);m_tcp->DeAllocate (m_endPoint);

      NS_ASSERT(m_endPoint==nullptr);NS_ASSERT(m_endPoint==nullptr);

    }}

  if(m_endPoint6!=nullptr)if(m_endPoint6!= nullptr)

    {{

      NS_ASSERT(m_tcp!=nullptr);NS_ASSERT(m_tcp!=nullptr);

      NS_ASSERT(m_endPoint6!=nullptr);NS_ASSERT(m_endPoint6!= nullptr);

      m_tcp->DeAllocate(m_endPoint6);m_tcp->DeAllocate(m_endPoint6);

      NS_ASSERT(m_endPoint6==nullptr);NS_ASSERT(m_endPoint6==nullptr);

    }}

  m_tcp=0;m_tcp=0;

  CancelAllTimers();CancelAllTimers();

}

Nhưng trong Python, chúng tôi không có tương đương với Delimit ____ 10 & nbsp; và & nbsp;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

async def main (indir):def main(indir):

& nbsp; & nbsp; & nbsp; & nbsp;# quét Dirs cho các tệp và điền vào danh sách# Scan dirs for files and populate a list

    filepaths=[]filepaths=[]

& nbsp;forpath, dirs,files inos.walk(indir):

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;forbasename infiles:

            filepath=os.path.join(path,basename)filepath =os.path.join(path,basename)

            filepaths.append(filepath)filepaths.append(filepath)

& nbsp; & nbsp; & nbsp; & nbsp; "" "Tạo" nhóm quy trình "của 4 và chạy asyncio."""Create the "process pool" of 4 and run asyncio.

& nbsp; & nbsp; & nbsp; & nbsp; các quy trình sẽ thực thi chức năng công nhân

& nbsp; & nbsp; & nbsp; & nbsp; đồng thời với mỗi đường dẫn tệp dưới dạng tham số

    """""

    loop=asyncio.get_running_loop()loop=asyncio.get_running_loop()

& nbsp; & nbsp; & nbsp; & nbsp; với đồng thời.with concurrent.futures.ProcessPoolExecutor(max_workers=4)asexecutor:

        futures=[loop.run_in_executor(executor,func,f)forfinfilepaths]futures= [loop.run_in_executor(executor,func,f)forfinfilepaths]

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;forfut in asyncio.as_completed(futures):

            try:try:

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;filepath=await fut

                print(filepath)print(filepath)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;except Exception asexc:

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;print("failed one job")

Điều này hoạt động bởi vì Python hỗ trợ tuyên bố một chuỗi theo nghĩa đen trải dài trên nhiều dòng nếu nó được phân định bằng dấu ngoặc kép ba (jedi7). Và một chuỗi theo nghĩa đen trong mã chỉ là một chuỗi được khai báo không có tác động. Do đó, nó có chức năng không khác gì các ý kiến.

Một lý do chúng tôi muốn sử dụng chuỗi chữ là để nhận xét một khối mã lớn. Ví dụ,

từ sklearn.linear_model nhập khẩu logisticregressionsklearn.linear_model import LogisticRegression

từ sklearn.datasets nhập make_classificationsklearn.datasets import make_classification

"" ""

X, y = make_classification (n_samples = 5000, n_features = 2, n_informative = 2,

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; n_redundant = 0, n_repeated = 0, n_ classes = 2,

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; n_clusters_per_class = 1,

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; Trọng lượng = [0,01, 0,05, 0,94],

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; class_sep = 0.8, Random_state = 0)

"" """

X, y = make_classification (n_samples = 5000, n_features = 2, n_informative = 2,pickle

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; n_redundant = 0, n_repeated = 0, n_ classes = 2,open("dataset.pickle","wb")asfp:

    X,y=pickle.load(fp)X,y= pickle.load(fp)

clf=LogisticRegression(random_state=0).fit(X,y)=LogisticRegression(random_state=0).fit(X,y)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; n_clusters_per_class = 1,..

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; Trọng lượng = [0,01, 0,05, 0,94],

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; class_sep = 0.8, Random_state = 0)

nhập khẩu dưa chuasquare(x):

Với Open ("DataSet.Pickle", "WB") ASFP:"""Just to compute the square of a value

    Args:

...

    Returns:

Trên đây là mã mẫu mà chúng tôi có thể phát triển bằng cách thử nghiệm vấn đề học máy. Mặc dù chúng tôi đã tạo một bộ dữ liệu một cách ngẫu nhiên ở đầu (cuộc gọi đến jedi8 ở trên), chúng tôi có thể muốn chuyển sang một bộ dữ liệu khác và lặp lại cùng một quy trình sau đó (ví dụ: phần Pickle ở trên). Thay vì xóa khối mã, chúng tôi có thể chỉ cần bình luận về các dòng đó để chúng tôi có thể lưu trữ mã sau. Nó không có hình dạng tốt cho mã hoàn thiện mà là thuận tiện trong khi phát triển giải pháp của chúng tôi.

    """""

Chuỗi theo nghĩa đen trong Python như một nhận xét có một mục đích đặc biệt nếu nó nằm trong dòng đầu tiên theo một hàm. Chuỗi theo nghĩa đen, trong trường hợp đó, được gọi là Doc DocString của chức năng. Ví dụ,returnx *x

bình phương def (x):

& nbsp; & nbsp; & nbsp; & nbsp; "" "Chỉ để tính toán bình phương của một giá trị("Function name:",square.__name__)

print("Docstring:",square.__doc__)("Docstring:",square.__doc__)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; x (int hoặc float)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

Args:

& nbsp; & nbsp; & nbsp; & nbsp; returnx *x

Returns:

Chúng ta có thể thấy dòng đầu tiên trong hàm là một chuỗi theo nghĩa đen và nó phục vụ mục đích tương tự như một nhận xét. Nó làm cho mã dễ đọc hơn, nhưng đồng thời, chúng ta có thể lấy nó từ mã:

in ("Tên chức năng:", Square .__ Name__)

Tên chức năng: vuông

Không có cách làm tiêu chuẩn để tạo tài liệu, nhưng nói chung, chúng tôi hy vọng họ sẽ giải thích mục đích của một hàm (hoặc một lớp hoặc mô -đun) cũng như các đối số và các giá trị trả về. Một phong cách phổ biến giống như ở trên, được Google ủng hộ. Một phong cách khác là từ Numpy:

bình phương def (x):square(x):

& nbsp; & nbsp; & nbsp; & nbsp; "" "Chỉ để tổng hợp bình phương của một giá trị"""Just to compupte the square of a value

    Parameters

    ----------

& nbsp; & nbsp; & nbsp; & nbsp; x: int hoặc float

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; một giá trị số

    Returns

    -------

& nbsp; & nbsp; & nbsp; & nbsp; int hoặc float

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

    """""

& nbsp; & nbsp; & nbsp; & nbsp; returnx *xreturnx *x

Các công cụ như AutoDoc có thể phân tích các tài liệu này và tạo tài liệu API. Nhưng ngay cả khi đó không phải là mục đích, có một tài liệu mô tả bản chất của hàm, các loại dữ liệu của các đối số hàm và giá trị trả về chắc chắn có thể giúp mã của bạn dễ đọc hơn. Điều này đặc biệt đúng vì Python, không giống như C ++ hoặc Java, là ngôn ngữ gõ vịt trong đó các biến và đối số chức năng không được khai báo với một loại cụ thể. Chúng tôi có thể sử dụng các tài liệu để đánh vần các giả định của kiểu dữ liệu để mọi người có thể dễ dàng theo dõi hoặc sử dụng chức năng của bạn hơn.duck-typing language in which variables and function arguments are not declared with a particular type. We can make use of docstrings to spell out the assumptions of the data type so people can more easily follow or use your function.

Bạn muốn bắt đầu với Python để học máy?

Tham gia khóa học gặp sự cố email 7 ngày miễn phí của tôi ngay bây giờ (với mã mẫu).

Nhấp để đăng ký và cũng nhận được phiên bản Ebook PDF miễn phí của khóa học.

Sử dụng các gợi ý loại trong mã Python

Vì Python 3.5, loại cú pháp gợi ý loại được cho phép. Như tên gọi, mục đích của nó là gợi ý về loại và không có gì khác. Do đó, ngay cả khi nó có vẻ đưa Python đến gần Java hơn, điều đó không có nghĩa là hạn chế dữ liệu được lưu trữ trong một biến. Ví dụ trên có thể được viết lại bằng một gợi ý loại:

def Square (x: int)-> int:square(x:int)->int:

& nbsp; & nbsp; & nbsp; & nbsp; returnx *xreturnx *x

Các công cụ như AutoDoc có thể phân tích các tài liệu này và tạo tài liệu API. Nhưng ngay cả khi đó không phải là mục đích, có một tài liệu mô tả bản chất của hàm, các loại dữ liệu của các đối số hàm và giá trị trả về chắc chắn có thể giúp mã của bạn dễ đọc hơn. Điều này đặc biệt đúng vì Python, không giống như C ++ hoặc Java, là ngôn ngữ gõ vịt trong đó các biến và đối số chức năng không được khai báo với một loại cụ thể. Chúng tôi có thể sử dụng các tài liệu để đánh vần các giả định của kiểu dữ liệu để mọi người có thể dễ dàng theo dõi hoặc sử dụng chức năng của bạn hơn.

def Square (x: int)-> int:square(x:int)->int:

Trong một hàm, các đối số có thể được theo sau bởi A & nbsp; ________ 19 & nbsp; cú pháp để đánh vần các loại & nbsp; dự định & nbsp; Giá trị trả về của một hàm được xác định bởi & nbsp; ____ ____ 20 cú pháp trước đại tràng. Trên thực tế, một gợi ý loại cũng có thể được khai báo cho các biến, ví dụ:value:int=x *x

    returnvaluereturnvalue

& nbsp; & nbsp; & nbsp; & nbsp; value: int = x *x

Lợi ích của một gợi ý loại là gấp đôi: chúng ta có thể sử dụng nó để loại bỏ một số nhận xét nếu chúng ta cần mô tả rõ ràng loại dữ liệu đang được sử dụng. Chúng tôi cũng có thể giúp các máy phân tích tĩnh hiểu mã của chúng tôi tốt hơn để chúng có thể giúp xác định các vấn đề tiềm năng trong mã.

Đôi khi loại có thể phức tạp, và do đó Python cung cấp mô -đun ____ 21 & nbsp; trong thư viện tiêu chuẩn của nó để giúp làm sạch cú pháp. Ví dụ, chúng ta có thể sử dụng & nbsp; Như sau:typing import Any,Union,List

Từ việc nhập nhập bất kỳ, liên minh, danh sáchsquare(x:Union[int,float])-> Union[int,float]:

& nbsp; & nbsp; & nbsp; & nbsp; returnx *xreturnx *x

Các công cụ như AutoDoc có thể phân tích các tài liệu này và tạo tài liệu API. Nhưng ngay cả khi đó không phải là mục đích, có một tài liệu mô tả bản chất của hàm, các loại dữ liệu của các đối số hàm và giá trị trả về chắc chắn có thể giúp mã của bạn dễ đọc hơn. Điều này đặc biệt đúng vì Python, không giống như C ++ hoặc Java, là ngôn ngữ gõ vịt trong đó các biến và đối số chức năng không được khai báo với một loại cụ thể. Chúng tôi có thể sử dụng các tài liệu để đánh vần các giả định của kiểu dữ liệu để mọi người có thể dễ dàng theo dõi hoặc sử dụng chức năng của bạn hơn.append(x:List[Any],y: Any)->None:

    x.append(y)x.append(y)

Bạn muốn bắt đầu với Python để học máy?

n:int=3.5:int=3.5

Tham gia khóa học gặp sự cố email 7 ngày miễn phí của tôi ngay bây giờ (với mã mẫu).="assign a string"

Nhấp để đăng ký và cũng nhận được phiên bản Ebook PDF miễn phí của khóa học.

Sử dụng các gợi ý loại trong mã Python

Vì Python 3.5, loại cú pháp gợi ý loại được cho phép. Như tên gọi, mục đích của nó là gợi ý về loại và không có gì khác. Do đó, ngay cả khi nó có vẻ đưa Python đến gần Java hơn, điều đó không có nghĩa là hạn chế dữ liệu được lưu trữ trong một biến. Ví dụ trên có thể được viết lại bằng một gợi ý loại:

def Square (x: int)-> int:

Trong một hàm, các đối số có thể được theo sau bởi A & nbsp; ________ 19 & nbsp; cú pháp để đánh vần các loại & nbsp; dự định & nbsp; Giá trị trả về của một hàm được xác định bởi & nbsp; ____ ____ 20 cú pháp trước đại tràng. Trên thực tế, một gợi ý loại cũng có thể được khai báo cho các biến, ví dụ:

& nbsp; & nbsp; & nbsp; & nbsp; value: int = x *x

Lợi ích của một gợi ý loại là gấp đôi: chúng ta có thể sử dụng nó để loại bỏ một số nhận xét nếu chúng ta cần mô tả rõ ràng loại dữ liệu đang được sử dụng. Chúng tôi cũng có thể giúp các máy phân tích tĩnh hiểu mã của chúng tôi tốt hơn để chúng có thể giúp xác định các vấn đề tiềm năng trong mã.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

Từ việc gõ danh sách nhập, tuple, máy phát điệntyping import List,Tuple,Generator

Nhập Pandas ASPDpandas aspd

Nhập ASNP NUMPYnumpy asnp

TrainingSampleGenerator=Generator[Tuple[np.ndarray,np.ndarray],None,None]= Generator[Tuple[np.ndarray,np.ndarray],None,None]

def lstm_gen (dữ liệu: pd.dataframe,lstm_gen(data:pd.DataFrame,

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; Dấu thời gian: int,timesteps:int,

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; Batch_Size: int)-> TrainingSampleGenerator:batch_size:int)->TrainingSampleGenerator:

& nbsp; & nbsp; & nbsp; & nbsp; "" "Trình tạo để sản xuất các mẫu ngẫu nhiên để đào tạo LSTM"""Generator to produce random samples for LSTM training

    Args:

& NBSP;

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

& nbsp;

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; được sản xuất từ ​​một cửa sổ có độ dài như vậy

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

    Yields:

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; từ dữ liệu đầu vào

    """""

& nbsp; & nbsp; & nbsp; & nbsp;input_columns =[cforcindata.columns ifc!="target"]

    batch:List[Tuple[pd.DataFrame,pd.Series]]=[]batch: List[Tuple[pd.DataFrame,pd.Series]]=[]

    whileTrue:whileTrue:

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# pick one start time and security

        whileTrue:whileTrue:

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# Start from a random point from the data and clip a window

            row=data["target"].sample()row= data["target"].sample()

            starttime=row.index[0]starttime=row.index[0]

            window:pd.DataFrame=data[starttime:].iloc[:timesteps]window: pd.DataFrame=data[starttime:].iloc[:timesteps]

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# If we are at the end of the DataFrame, we can't get a full

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# window and we must start over

            iflen(window)==timesteps:iflen(window)==timesteps:

                breakbreak

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# trích xuất# Extract the input and output

        y=window["target"]y=window["target"]

        X=window[input_columns]X=window[input_columns]

        batch.append((X,y))batch.append((X, y))

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;# If accumulated enough for one batch, dispatch

        iflen(batch)==batch_size:iflen(batch)==batch_size:

            X,y=zip(*batch)X, y=zip(*batch)

& nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; ")yield np.array(X).astype("float32"), np.array(y).astype("float32")

            batch=[]batch=[]

đọc thêm

Phần này cung cấp nhiều tài nguyên hơn về chủ đề nếu bạn đang muốn đi sâu hơn.

Bài viết

  • Thực tiễn tốt nhất để viết nhận xét mã, & nbsp; https: //stackoverflow.blog/2021/12/23/best-practices-for-writing-code-comments/
  • PEP483, Lý thuyết về gợi ý loại, & nbsp; https: //www.python.org/dev/peps/pep-0483/
  • Hướng dẫn theo phong cách Google Python, & nbsp; https: //google.github.io/styleguide/pyguide.html

Phần mềm

  • Tài liệu Sphinx, & NBSP; https: //www.sphinx-doc.org/en/master/index.html
  • Mô-đun Napoleon của Sphinx, & NBSP; https: //sphinxcontrib-napoleon.readthedocs.io/en/latest/index.html
    • Ví dụ về tài liệu theo phong cách Google: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
    • Ví dụ về tài liệu theo phong cách Numpy: https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html
  • pdoc, https://pdoc.dev/
  • Mô -đun gõ, & nbsp; https: //docs.python.org/3/l Library/typing.html

Bản tóm tắt

Trong hướng dẫn này, bạn đã thấy cách chúng ta nên sử dụng các bình luận, tài liệu và gõ gợi ý trong Python. Cụ thể, bây giờ bạn đã biết:

  • Cách viết một bình luận tốt, hữu ích
  • Các quy ước trong việc giải thích một chức năng bằng cách sử dụng tài liệu
  • Cách sử dụng gợi ý loại để giải quyết điểm yếu dễ đọc của việc gõ vịt trong Python

Nhận một xử lý trên Python để học máy!

Hướng dẫn python docstring vs type hints - python docstring so với gợi ý về loại

Tự tin hơn để viết mã trong Python

... Từ việc học các thủ thuật trăn thực tế

Khám phá cách trong ebook mới của tôi: Python cho học máy
Python for Machine Learning

Nó cung cấp các hướng dẫn tự học với hàng trăm mã làm việc để trang bị cho bạn các kỹ năng bao gồm: gỡ lỗi, hồ sơ, gõ vịt, trang trí, triển khai, và nhiều hơn nữa ...self-study tutorials with hundreds of working code to equip you with skills including:
debugging, profiling, duck typing, decorators, deployment, and much more...

Hiển thị cho bạn hộp công cụ Python ở mức cao cho các dự án của bạn
Your Projects

Xem những gì bên trong

Bạn có nên sử dụng gợi ý loại Python?

Trong bài viết xuất sắc của mình, trạng thái của các gợi ý loại trong Python Bernátbor khuyến nghị rằng nên sử dụng gợi ý loại của loại bất cứ khi nào các bài kiểm tra đơn vị đáng để viết. Thật vậy, gõ gợi ý đóng một vai trò tương tự như các bài kiểm tra trong mã của bạn: chúng giúp bạn như một nhà phát triển viết mã tốt hơn.type hints should be used whenever unit tests are worth writing.” Indeed, type hints play a similar role as tests in your code: they help you as a developer write better code.

Các gợi ý loại có làm cho Python nhanh hơn không?

Không, gõ gợi ý không buộc Python phải kiểm tra loại dữ liệu được lưu trữ trong một biến.Chúng chỉ dành cho tài liệu tham khảo của nhà phát triển và giúp tự động hoàn thành phần mềm.Chúng cho phép IDE nhận ra các loại dữ liệu và đưa ra đề xuất dựa trên thông tin này.. They are just for the developer's reference and help auto-completion software. They allow IDEs to recognise data types and give suggestions based on this information.

__ init __ có một tài liệu?

Tất cả các mô -đun thường có tài liệu, và tất cả các chức năng và lớp được xuất bằng một mô -đun cũng nên có tài liệu.Phương pháp công khai (bao gồm cả hàm tạo __init__) cũng nên có tài liệu.Public methods (including the __init__ constructor) should also have docstrings.

Khi nào bạn nên sử dụng một tài liệu?

Như đã đề cập ở trên, các tài liệu Python là các chuỗi được sử dụng ngay sau khi định nghĩa về hàm, phương thức, lớp hoặc mô -đun (như trong ví dụ 1).Chúng được sử dụng để ghi lại mã của chúng tôi.right after the definition of a function, method, class, or module (like in Example 1). They are used to document our code.