Nếu bạn đang cố gắng gỡ lỗi hoặc hiểu một đoạn mã Python, đôi khi không đủ để chỉ chạy nó trong đầu của bạn. May mắn thay, có một số công cụ tuyệt vời có thể giúp bạn ra ngoài.
Cách tốt nhất để có được người gọi chức năng Python trong chương trình là sử dụng trình gỡ lỗi. Thay vào đó, nếu bạn muốn lấy thông tin này theo chương trình, bạn có thể phân tích dấu vết ngăn xếp cuộc gọi với gói inspect
.
Tôi sẽ hiển thị cho bạn cả hai phương pháp và cũng trình bày một giải pháp thay thế thứ ba - sử dụng Trình hiển thị thực thi.
Lấy người gọi bằng trình gỡ lỗi
Ưu điểm của việc sử dụng trình gỡ lỗi, là bạn không phải sửa đổi mã chương trình thực tế.
Nó không thể được sử dụng trong chương trình của bạn - vì bạn cần sử dụng inspect
, vì vậy nếu bạn muốn đưa ra quyết định trong mã của mình dựa trên người gọi, hãy thoải mái bỏ qua phần tiếp theo.in your program - for that you need to use inspect
, so if you want to make decisions in your code based on the caller, than feel free to skip ahead to the next section.
Trình gỡ lỗi là gì?
Trình gỡ lỗi là một công cụ phần mềm, được sử dụng để kiểm tra các chương trình, nó chủ yếu được sử dụng để điều tra các lỗi hoặc các vấn đề về hiệu suất. Trình gỡ lỗi cho phép bạn tạm dừng, khởi động lại hoặc thậm chí thực hiện từng bước của chương trình. Bạn cũng có thể tương tác kiểm tra hoặc sửa đổi các biến trong chương trình của bạn trong khi nó đang chạy.
Làm quen với một trình gỡ lỗi cần một chút thực hành, nhưng đó là một kỹ năng rất có giá trị, mọi nhà phát triển phần mềm tham vọng nên dành thời gian để làm quen với việc sử dụng một.
PDB là gì?
Nếu bạn đã cài đặt Python trên máy của mình, bạn đã có trình gỡ lỗi, vì Python theo mặc định các tàu với mô -đun
python3 -m pdb whocalled.py
1 - Trình gỡ lỗi Python.Tôi sẽ chỉ cho bạn cách bạn có thể sử dụng
python3 -m pdb whocalled.py
1 với sự trợ giúp của một ví dụ đơn giản. Tôi sẽ sử dụng kịch bản nhỏ này để trình diễn:def called_function[]:
print["I am called"]
def caller_function[]:
print["I am the caller"]
called_function[]
caller_function[]
Mục tiêu của chúng tôi là dừng chương trình đang chạy khi
python3 -m pdb whocalled.py
3 được thực hiện và tìm ra nơi nó được gọi.Bắt đầu PDB
Đầu tiên, chúng ta cần bắt đầu tập lệnh với
python3 -m pdb whocalled.py
1:python3 -m pdb whocalled.py
Điều này sẽ tải tập lệnh, nhưng tạm dừng thực hiện trước dòng đầu tiên. PDB sẽ in dòng mà chúng tôi đang đứng, và sau đó cung cấp cho chúng tôi lời nhắc
python3 -m pdb whocalled.py
5 tương tác.> /pythonin1minute/whocalled.py[1][]
-> def called_function[]:
[Pdb]
Đặt điểm dừng - bảo PDB tạm dừng tại một điểm nhất định
Để thực hiện tạm dừng
python3 -m pdb whocalled.py
1 tại python3 -m pdb whocalled.py
3, chúng tôi sẽ cần đặt cái gọi là điểm dừng. Khi việc thực hiện đạt đến điểm dừng, trình gỡ lỗi sẽ tạm dừng chương trình và đưa chúng tôi trở lại lời nhắc tương tác, vì vậy chúng tôi sẽ có thể kiểm tra trạng thái của chương trình.breakpoint. When the execution reaches a breakpoint the debugger pauses the program and gives us
back to interactive prompt, so we’ll be able to inspect the state of the program.Một điểm dừng có thể được tạo với lệnh
python3 -m pdb whocalled.py
8. Là đối số đầu tiên của nó, chúng ta có thể chỉ định tên tệp và số dòng hoặc tên hàm. Chúng tôi sẽ sử dụng tên chức năng python3 -m pdb whocalled.py
3:[Pdb] break called_function
Tiếp tục - tiếp tục thực thi cho đến khi chúng tôi đạt đến điểm dừng
Chúng ta có thể để tập lệnh chạy với lệnh
> /pythonin1minute/whocalled.py[1][]
-> def called_function[]:
[Pdb]
0. Nó sẽ dừng ở điểm dừng tiếp theo hoặc khi chương trình hoàn thành việc thực thi.Làm cho PDB in dấu vết ngăn xếp cuộc gọi
> /pythonin1minute/whocalled.py[1][]
-> def called_function[]:
[Pdb]
1 sẽ dừng lại ở điểm dừng mà chúng tôi đã đặt tại python3 -m pdb whocalled.py
3:I am the caller
> /pythonin1minute/whocalled.py[2]called_function[]
-> print["I am called"]
Bây giờ, chúng ta có thể sử dụng lệnh
> /pythonin1minute/whocalled.py[1][]
-> def called_function[]:
[Pdb]
3 để in dấu vết ngăn xếp.[PDB] ở đâu
/home/linuxbrew/.linuxbrew/Cellar/python/3.7.6_1/lib/python3.7/bdb.py[585]run[]
-> exec[cmd, globals, locals]
[1][]
/pythonin1minute/whocalled.py[8][]
-> caller_function[]
/pythonin1minute/whocalled.py[6]caller_function[]
-> called_function[]
> /pythonin1minute/whocalled.py[2]called_function[]
-> print["I am called"]
Như bạn có thể thấy dấu vết ngăn xếp về cơ bản là một danh sách của chuỗi cuộc gọi, với cuộc gọi mới nhất ở phía dưới. Bạn có thể đọc nó ngược - từ dưới lên:
4 đang được gọi bởi> /pythonin1minute/whocalled.py[1][] -> def called_function[]: [Pdb]
3python3 -m pdb whocalled.py
3 đang được gọi bởipython3 -m pdb whocalled.py
7> /pythonin1minute/whocalled.py[1][] -> def called_function[]: [Pdb]
7 đang được gọi bởi> /pythonin1minute/whocalled.py[1][] -> def called_function[]: [Pdb]
9> /pythonin1minute/whocalled.py[1][] -> def called_function[]: [Pdb]
Toàn bộ phiên
python3 -m pdb whocalled.py
1 này để kiểm tra chuỗi cuộc gọi chức năng trông giống như thế này:Giao diện trực quan cho Debuggers
> /pythonin1minute/whocalled.py[1][]
-> def called_function[]:
[Pdb]
1 rất mạnh mẽ, nhưng giao diện dòng lệnh không phải là giao diện trực quan hoặc linh hoạt nhất. May mắn thay, hầu hết các IDE hiện đại - như Pycharm hoặc Visual Studio Code - cung cấp một giao diện trực quan thân thiện hơn để gỡ lỗi.Mã trực quan mã
Một cách tốt đẹp khác để kiểm tra việc thực thi mã của bạn là sử dụng trình hiển thị mã. Nó có chính xác cơ chế giống như sử dụng trình gỡ lỗi, nhưng bạn có được hình dung tốt về cách thực thi chương trình của bạn.
Nếu bạn đang cố gắng hiểu một đoạn trích nhỏ hơn, bạn có thể sử dụng trình hiển thị trực tuyến tại pythontutor.com. Nó rất tuyệt vời cho mục đích giáo dục.
Chạy qua ví dụ trước, tôi có một biểu đồ thực thi nhỏ đẹp:
Nhận người gọi bằng inspect
Mô -đun inspect
cung cấp các công cụ của nhà phát triển để kiểm tra trạng thái chương trình hiện tại, bạn có thể nhận được rất nhiều thông tin thời gian chạy hữu ích về các đối tượng và biến của bạn.
Nếu bạn muốn đưa ra quyết định dựa trên người gọi của chức năng thì đây là cách để đi.
Lưu ý: Hầu hết thời gian đây không phải là một ý tưởng tốt và - trừ khi bạn thực sự biết những gì bạn đang làm - có lẽ bạn nên sửa đổi kiến trúc chương trình của bạn. Có một vài trường hợp đặc biệt, nhưng nhìn chung, các chức năng chỉ nên giao tiếp với người gọi của họ thông qua các phương tiện thường xuyên, ví dụ: đối số và giá trị trả về của họ.
Nhận ngăn xếp trong thời gian chạy
Mô -đun inspect
xác định chức năng tiện ích được gọi là
[Pdb] break called_function
5 mà chúng ta có thể sử dụng để truy xuất ngăn xếp cuộc gọi.Gọi
[Pdb] break called_function
6 Trả về một danh sách, trong đó phần tử đầu tiên là cuộc gọi cuối cùng [hàm chúng ta gọi [Pdb] break called_function
6 từ], phần tử thứ hai là hàm gọi chúng ta, v.v.Mỗi phần tử trả về một
[Pdb] break called_function
8, có thuộc tính [Pdb] break called_function
9, trả về tên hàm. Nó có nghĩa là chúng ta có thể có được người gọi như thế này:from inspect import stack
stack[][1].function
Vì vậy, trở lại ví dụ trước của chúng tôi, chúng tôi có thể làm một cái gì đó như:
from inspect import stack
def called_function[]:
print["CALLER FUNCTION: {}".format[stack[][1].function]]
print["I am being called"]
def caller_function[]:
print["I am the caller"]
called_function[]
caller_function[]
Đầu ra sẽ là:
I am the caller
CALLER FUNCTION: caller_function
I am being called