Máy tính Python với lịch sử

Để kết thúc chương này, tôi sẽ chỉ cho bạn một ứng dụng thực tế của một số công nghệ phân tích cú pháp được giới thiệu trong phần trước. Phần này trình bày PyCalc -- một chương trình máy tính Python có giao diện đồ họa tương tự như các chương trình máy tính có sẵn trên hầu hết các hệ thống cửa sổ. Nhưng giống như hầu hết các ví dụ về GUI trong cuốn sách này, PyCalc cung cấp một số ưu điểm so với các máy tính hiện có. Vì PyCalc được viết bằng Python nên nó vừa dễ dàng tùy chỉnh vừa có thể di chuyển rộng rãi trên các nền tảng cửa sổ. Và bởi vì nó được triển khai với các lớp, nó vừa là một chương trình độc lập vừa là một thư viện đối tượng có thể tái sử dụng

7. 1 GUI máy tính đơn giản

Tuy nhiên, trước khi tôi chỉ cho bạn cách viết một máy tính toàn diện, mô-đun hiển thị trong Ví dụ 18-13 sẽ bắt đầu cuộc thảo luận này bằng các thuật ngữ đơn giản hơn. Nó triển khai một GUI máy tính giới hạn, có các nút chỉ cần thêm văn bản vào trường nhập ở trên cùng, để soạn một chuỗi biểu thức Python. Tìm nạp và chạy tất cả chuỗi cùng một lúc sẽ tạo ra kết quả. Hình 18-8 hiển thị cửa sổ mà mô-đun này tạo ra khi chạy dưới dạng tập lệnh cấp cao nhất

Hình 18-8. Tập lệnh calc0 đang hoạt động trên Windows [result=160. 283]
Ví dụ 18-13. PP2ELangMáy tínhcalc0. py
#!/usr/local/bin/python
# a simple calculator GUI: expressions run all at once with eval/exec

from Tkinter import * 
from PP2E.Dbase.TableBrowser.guitools import frame, button, entry

class CalcGui[Frame]:
 def __init__[self, parent=None]: # an extended frame
 Frame.__init__[self, parent] # on default top-level
 self.pack[expand=YES, fill=BOTH] # all parts expandable
 self.master.title[Python Calculator 0.1] # 6 frames plus entry
 self.master.iconname["pcalc1"]

 self.names = {} # namespace for variables
 text = StringVar[ ]
 entry[self, TOP, text]

 rows = ["abcd", "0123", "4567", "89[ ]"]
 for row in rows:
 frm = frame[self, TOP]
 for char in row: button[frm, LEFT, char, 
 lambda x=text, y=char: x.set[x.get[ ] + y]]

 frm = frame[self, TOP]
 for char in "+-*/=": button[frm, LEFT, char,
 lambda x=text, y=char: x.set[x.get[ ]+ +y+ ]]

 frm = frame[self, BOTTOM]
 button[frm, LEFT, eval, lambda x=self, y=text: x.eval[y] ]
 button[frm, LEFT, clear, lambda x=text: x.set[\] ]

 def eval[self, text]:
 try:
 text.set[`eval[text.get[ ], self.names, self.names]`]
 except SyntaxError:
 try:
 exec[text.get[ ], self.names, self.names] 
 except:
 text.set["ERROR"] # bad as statement too?
 else:
 text.set[\] # worked as a statement
 except:
 text.set["ERROR"] # other eval expression errors

if __name__ == \__main__: CalcGui[].mainloop[ ]
7. 1. 1 Xây dựng GUI

Bây giờ, điều này đơn giản như một máy tính có thể, nhưng nó thể hiện những điều cơ bản. Cửa sổ này xuất hiện các nút để nhập số, tên biến và toán tử. Nó được xây dựng bằng cách gắn các nút vào khung. mỗi hàng nút là một Khung lồng nhau và bản thân GUI là một lớp con Khung, với Mục nhập được đính kèm và sáu khung hàng được nhúng [lưới cũng sẽ hoạt động ở đây]. Khung máy tính, trường nhập và các nút có thể mở rộng trong mô-đun tiện ích guitools đã nhập

Máy tính này tạo ra một chuỗi để chuyển đến trình thông dịch Python cùng một lúc khi nhấn nút "eval". Vì bạn có thể nhập bất kỳ biểu thức hoặc câu lệnh Python nào vào trường nhập, nên các nút thực sự chỉ là một tiện ích. Trên thực tế, trường nhập không chỉ là một dòng lệnh. Hãy thử nhập import sys và sau đó dir[sys] để hiển thị các thuộc tính mô-đun sys trong trường nhập ở trên cùng -- đó không phải là điều bạn thường làm với máy tính, nhưng vẫn mang tính minh họa. [3]

[3] Và một lần nữa, tôi cần cảnh báo bạn về việc chạy các chuỗi như thế này nếu bạn có thể chắc chắn rằng chúng sẽ gây ra thiệt hại. Xem mô-đun chế độ thực thi hạn chế rexec trong Chương 15, để biết thêm chi tiết

Trong hàm tạo CalcGuis, các nút được mã hóa dưới dạng danh sách các chuỗi; . Lambda với các giá trị đối số mặc định được sử dụng để đặt dữ liệu gọi lại cho mỗi nút. Các hàm gọi lại lưu các ký tự của nút và biến mục nhập văn bản được liên kết, để ký tự có thể được thêm vào cuối chuỗi hiện tại của widget mục nhập khi nhấn

Bài học 4 Nhúng trình phân tích nhịp phách

Máy tính sử dụng eval và exec để gọi trình phân tích cú pháp/trình thông dịch Pythons trong thời gian chạy thay vì phân tích và đánh giá các biểu thức theo cách thủ công. Trên thực tế, máy tính chạy mã Python nhúng từ chương trình Python. Điều này hoạt động vì môi trường phát triển Pythons [trình phân tích cú pháp và trình biên dịch mã byte] luôn là một phần của các hệ thống sử dụng Python. Do không có sự khác biệt giữa môi trường phát triển và phân phối, trình phân tích cú pháp Python có thể được sử dụng bởi các chương trình Python

Hiệu ứng ròng ở đây là toàn bộ trình đánh giá biểu thức đã được thay thế bằng một lệnh gọi duy nhất để đánh giá. Nói rộng hơn, đây là một kỹ thuật hiệu quả để ghi nhớ. bản thân ngôn ngữ Python có thể thay thế nhiều ngôn ngữ tùy chỉnh nhỏ. Bên cạnh việc tiết kiệm thời gian phát triển, khách hàng chỉ phải học một ngôn ngữ, một ngôn ngữ đủ đơn giản để mã hóa người dùng cuối

Hơn nữa, Python có thể mang hương vị của bất kỳ ứng dụng nào. Nếu một giao diện ngôn ngữ yêu cầu các tiện ích mở rộng dành riêng cho ứng dụng, chỉ cần thêm các lớp Python hoặc xuất API để sử dụng trong mã Python được nhúng dưới dạng tiện ích mở rộng C. Bằng cách đánh giá mã Python sử dụng các tiện ích mở rộng dành riêng cho ứng dụng, trình phân tích cú pháp tùy chỉnh trở nên gần như hoàn toàn không cần thiết

Ngoài ra còn có một lợi ích bổ sung quan trọng cho phương pháp này. mã nhúng Python có quyền truy cập vào tất cả các công cụ và tính năng của ngôn ngữ lập trình mạnh mẽ, toàn diện. Nó có thể sử dụng danh sách, hàm, lớp, mô-đun bên ngoài và thậm chí các công cụ Python lớn hơn như Tkinter, kệ, luồng và ổ cắm. Bạn có thể dành nhiều năm để cố gắng cung cấp chức năng tương tự trong trình phân tích cú pháp ngôn ngữ tùy chỉnh. Chỉ cần hỏi Guido

7. 1. 2 Chuỗi mã chạy

Mô-đun này thực hiện một máy tính GUI trong 45 dòng mã [đếm nhận xét và dòng trống]. Nhưng thành thật mà nói, nó gian lận. đánh giá biểu thức được ủy quyền cho Python. Trên thực tế, các công cụ eval và exec tích hợp thực hiện hầu hết công việc ở đây

  • eval phân tích cú pháp, đánh giá và trả về kết quả của biểu thức Python được biểu thị dưới dạng chuỗi
  • exec chạy một câu lệnh Python tùy ý được biểu diễn dưới dạng một chuỗi;

Cả hai đều chấp nhận từ điển tùy chọn được sử dụng làm không gian tên toàn cầu và cục bộ để gán và đánh giá tên được sử dụng trong chuỗi mã. Trong máy tính, tự. tên trở thành một bảng ký hiệu để chạy các biểu thức máy tính. Có thể sử dụng một hàm Python có liên quan, biên dịch, để biên dịch trước các chuỗi mã trước khi chuyển chúng tới eval và exec [hãy sử dụng hàm này nếu bạn cần chạy cùng một chuỗi nhiều lần]

Theo mặc định, không gian tên chuỗi mã mặc định cho không gian tên người gọi. Nếu chúng ta không chuyển vào từ điển ở đây, các chuỗi sẽ chạy trong không gian tên phương thức eval. Vì không gian tên cục bộ của phương thức biến mất sau khi lệnh gọi phương thức trả về, sẽ không có cách nào để giữ lại các tên được gán trong chuỗi. Lưu ý việc sử dụng các trình xử lý ngoại lệ lồng nhau trong phương thức eval

  • Đầu tiên, nó giả sử chuỗi là một biểu thức và thử hàm eval tích hợp
  • Nếu không thành công do lỗi cú pháp, nó sẽ thử đánh giá chuỗi dưới dạng câu lệnh bằng cách sử dụng exec
  • Cuối cùng, nếu cả hai lần thử đều thất bại, nó sẽ báo lỗi trong chuỗi [lỗi cú pháp, tên không xác định, v.v. ]

Các câu lệnh và biểu thức không hợp lệ có thể được phân tích cú pháp hai lần, nhưng chi phí không thành vấn đề ở đây và bạn có thể biết liệu một chuỗi là một biểu thức hay một câu lệnh mà không cần phân tích cú pháp theo cách thủ công. Lưu ý rằng nút "eval" đánh giá các biểu thức, nhưng = đặt các biến Python bằng cách chạy câu lệnh gán. Tên biến là tổ hợp của các phím chữ cái abcd [hoặc bất kỳ tên nào được gõ trực tiếp]. Chúng được chỉ định và đánh giá trong một từ điển được sử dụng để đại diện cho không gian tên máy tính

7. 1. 3 Mở rộng và đính kèm

Khách hàng sử dụng lại máy tính này cũng đơn giản như chính máy tính. Giống như hầu hết các GUI Tkinter dựa trên lớp, giao diện này có thể được mở rộng trong các lớp con -- Ví dụ 18-14 tùy chỉnh hàm tạo máy tính đơn giản để thêm các tiện ích bổ sung

Ví dụ 18-14. PP2ELangMáy tínhcalc0ext. py
from Tkinter import *
from calc0 import CalcGui

class Inner[CalcGui]: # extend gui
 def __init__[self]:
 CalcGui.__init__[self]
 Label[self, text=Calc Subclass].pack[ ] # add after
 Button[self, text=Quit, command=self.quit].pack[ ] # top implied
 
Inner[].mainloop[ ]

Nó cũng có thể được nhúng trong một lớp vùng chứa -- Ví dụ 18-15 gắn gói tiện ích máy tính đơn giản và các gói bổ sung vào một gói cha chung

Ví dụ 18-15. PP2ELangMáy tínhcalc0emb. py
from Tkinter import *
from calc0 import CalcGui # add parent, no master calls

class Outer:
 def __init__[self, parent]: # embed gui
 Label[parent, text=Calc Attachment].pack[ ] # side=top
 CalcGui[parent] # add calc frame
 Button[parent, text=Quit, command=parent.quit].pack[ ] 
 
root = Tk[ ]
Outer[root]
root.mainloop[ ]

Hình 18-9 cho thấy kết quả của việc chạy cả hai tập lệnh này từ các dòng lệnh khác nhau. Cả hai đều có một trường đầu vào riêng biệt ở trên cùng. Những công việc này;

Hình 18-9. Đối tượng tập lệnh calc0 được đính kèm và mở rộng

7. 2 Pycalc - GUI máy tính thực

Tất nhiên, máy tính thực tế thường không hoạt động bằng cách xây dựng các chuỗi biểu thức và đánh giá tất cả chúng cùng một lúc; . Theo truyền thống, các biểu thức được đánh giá theo kiểu từng phần khi chúng được nhập và kết quả tạm thời được hiển thị ngay khi chúng được tính toán. Thực hiện hành vi này là một công việc nhiều hơn một chút. các biểu thức phải được đánh giá thủ công thay vì chỉ gọi hàm eval một lần. Nhưng kết quả cuối cùng hữu ích và trực quan hơn nhiều

Bài học 5 Khả năng tái sử dụng là sức mạnh

Mặc dù đơn giản, việc gắn và phân loại máy tính bằng đồ họa, như trong Hình 18-9, minh họa sức mạnh của Python như một công cụ để viết phần mềm có thể tái sử dụng. Bằng cách mã hóa các chương trình với các mô-đun và các lớp, các thành phần được viết tách biệt gần như tự động trở thành các công cụ có mục đích chung. Các tính năng tổ chức chương trình của Pythons thúc đẩy mã có thể tái sử dụng

Trên thực tế, tái sử dụng mã là một trong những thế mạnh chính của Python và là một trong những chủ đề chính của cuốn sách này cho đến nay. Thiết kế hướng đối tượng tốt cần một số thực hành và suy nghĩ trước, và lợi ích của việc sử dụng lại mã sẽ rõ ràng ngay lập tức. Và đôi khi chúng tôi quan tâm đến việc sửa chữa nhanh hơn là việc sử dụng mã trong tương lai

Nhưng mã hóa với một số khả năng sử dụng lại có thể tiết kiệm thời gian phát triển về lâu dài. Ví dụ: trình phân tích cú pháp được mã hóa bằng tay đã chia sẻ máy quét, GUI máy tính sử dụng mô-đun guitools mà chúng ta đã thảo luận trước đó và ví dụ tiếp theo sẽ sử dụng lại lớp GuiMixin. Đôi khi chúng ta có thể hoàn thành một phần công việc trước khi bắt đầu

Phần này trình bày cách triển khai PyCalc -- một chương trình Python/Tkinter triển khai GUI máy tính truyền thống như vậy. Mặc dù logic đánh giá của nó phức tạp hơn máy tính đơn giản hơn ở trên, nhưng nó thể hiện các kỹ thuật lập trình nâng cao và đóng vai trò là phần cuối thú vị cho chương này

7. 2. 1 Chạy PyCalc

Như thường lệ, hãy xem GUI trước khi viết mã. Bạn có thể chạy PyCalc từ thanh trình khởi chạy PyGadgets và PyDemos ở đầu cây ví dụ hoặc bằng cách chạy trực tiếp máy tính tệp. py được liệt kê dưới đây [e. g. , nhấp vào nó trong trình khám phá tệp]. Hình 18-10 hiển thị cửa sổ chính của PyCalcs. Theo mặc định, nó hiển thị các nút toán hạng có màu đen trên xanh lam [và ngược lại với các nút của người vận hành], nhưng các tùy chọn phông chữ và màu sắc có thể được chuyển vào phương thức khởi tạo của lớp GUI. Tất nhiên, điều đó có nghĩa là màu xám trên màu xám trong cuốn sách này, vì vậy bạn sẽ phải tự chạy PyCalc để xem ý tôi là gì

Hình 18-10. Máy tính PyCalc đang hoạt động trên Windows

Nếu bạn chạy chương trình này, bạn sẽ nhận thấy rằng PyCalc thực hiện một mô hình máy tính thông thường -- các biểu thức được đánh giá là đã nhập, không phải tất cả cùng một lúc ở cuối. Nghĩa là, các phần của một biểu thức được tính toán và hiển thị ngay khi quyền ưu tiên của toán tử và các dấu ngoặc đơn được nhập thủ công cho phép. Tôi sẽ giải thích cách đánh giá này hoạt động trong giây lát

Lớp PyCalcs CalcGui xây dựng giao diện GUI dưới dạng các khung nút giống như máy tính đơn giản của phần trước, nhưng PyCalc bổ sung thêm nhiều tính năng mới. Trong số đó có một hàng nút hành động khác, các phương thức kế thừa từ GuiMixin [được trình bày trong Chương 9], một nút "cmd" mới bật lên các hộp thoại phi phương thức để nhập mã Python tùy ý và một cửa sổ bật lên lịch sử tính toán gần đây. Hình 18-11 chụp một số cửa sổ bật lên của PyCalcs

Hình 18-11. Máy tính PyCalc với một số cửa sổ bật lên của nó

Bạn có thể nhập các biểu thức trong PyCalc bằng cách nhấp vào các nút trong GUI, nhập các biểu thức đầy đủ trong cửa sổ bật lên dòng lệnh hoặc nhập các phím trên bàn phím của bạn. PyCalc chặn các sự kiện nhấn phím và diễn giải chúng giống như các lần nhấn nút tương ứng;

Các cửa sổ bật lên dòng lệnh không theo chế độ [bạn có thể bật lên bao nhiêu tùy thích]. Họ chấp nhận bất kỳ mã Python nào -- nhấn nút Chạy hoặc phím Enter của bạn để đánh giá văn bản trong trường nhập liệu. Kết quả đánh giá mã này trong từ điển không gian tên máy tính được đưa lên trong cửa sổ chính, để sử dụng trong các biểu thức lớn hơn. Bạn có thể sử dụng điều này như một cơ chế thoát hiểm để sử dụng các công cụ bên ngoài trong tính toán của mình. Chẳng hạn, bạn có thể nhập và sử dụng các hàm được mã hóa bằng Python hoặc C trong các cửa sổ bật lên này. Giá trị hiện tại trong cửa sổ máy tính chính cũng được lưu trữ trong cửa sổ bật lên dòng lệnh mới mở để sử dụng trong các biểu thức đã nhập

PyCalc hỗ trợ các số nguyên dài [độ chính xác không giới hạn], số âm và số dấu phẩy động, chỉ vì Python hỗ trợ. các toán hạng và biểu thức riêng lẻ vẫn được đánh giá với tích hợp eval, gọi trình phân tích cú pháp/trình thông dịch Python trong thời gian chạy. Tên biến có thể được gán và tham chiếu trong cửa sổ chính bằng các phím chữ cái, = và "eval"; . Lưu ý việc sử dụng số pi trong cửa sổ lịch sử. PyCalc nhập trước các tên trong các mô-đun toán học và ngẫu nhiên vào không gian tên nơi các biểu thức được đánh giá

7. 2. 2 Đánh giá các biểu thức với ngăn xếp

Bây giờ bạn đã có ý tưởng chung về những gì PyCalc làm, tôi cần nói một chút về cách thức hoạt động của nó. Hầu hết các thay đổi trong phiên bản này liên quan đến việc quản lý hiển thị biểu thức và đánh giá biểu thức. PyCalc được cấu trúc thành hai lớp

  • Lớp CalcGui tự quản lý GUI. Nó kiểm soát các sự kiện đầu vào và chịu trách nhiệm về trường hiển thị cửa sổ chính ở trên cùng. Tuy nhiên, nó không đánh giá các biểu thức;
  • Lớp Evaluator quản lý hai ngăn xếp. Một ngăn xếp ghi lại các toán tử đang chờ xử lý [e. g. , +] và một bản ghi các toán hạng đang chờ xử lý [e. g, 3. 141]. Các kết quả tạm thời được tính toán khi các toán tử mới được gửi từ CalcGui và được đẩy vào ngăn xếp toán hạng

Như bạn có thể thấy từ điều này, sự kỳ diệu của việc đánh giá biểu thức tóm lại là tung hứng toán tử và ngăn xếp toán hạng. Trong khi quét các chuỗi biểu thức từ trái sang phải khi chúng được nhập, các toán hạng được đẩy dọc theo đường đi, nhưng các toán tử phân định các toán hạng và có thể kích hoạt các kết quả tạm thời trước khi chúng được đẩy. Đây là kịch bản chung

  • Khi một toán tử mới được nhìn thấy [i. e. , khi một nút hoặc phím toán tử được nhấn], toán hạng trước trong trường mục nhập được đẩy vào ngăn xếp toán hạng
  • Toán tử sau đó được thêm vào ngăn xếp toán tử, nhưng chỉ sau khi tất cả các toán tử đang chờ xử lý có mức độ ưu tiên cao hơn đã được bật và áp dụng cho các toán hạng đang chờ xử lý [e. g. , nhấn + làm cho bất kỳ toán tử * đang chờ xử lý nào trên ngăn xếp kích hoạt]
  • Khi nhấn "eval", tất cả các toán tử còn lại sẽ được bật lên và áp dụng cho tất cả các toán hạng còn lại và kết quả là giá trị còn lại cuối cùng trên ngăn xếp toán hạng

Cuối cùng, giá trị cuối cùng trên ngăn xếp toán hạng được hiển thị trong trường nhập máy tính, sẵn sàng để sử dụng trong thao tác khác. Thuật toán đánh giá này có lẽ được mô tả tốt nhất bằng cách làm việc thông qua các ví dụ. Hãy xem qua mục nhập của một vài biểu thức và xem ngăn xếp đánh giá phát triển

Theo dõi ngăn xếp PyCalc được bật với cờ gỡ lỗi trong mô-đun; . Một bộ chứa danh sách ngăn xếp [toán tử, toán hạng] được in trên mỗi lần rút gọn ngăn xếp; . Chẳng hạn, đây là đầu ra của bàn điều khiển sau khi nhập và đánh giá một chuỗi đơn giản

1] Entered keys: "5 * 3 + 4 " [result = 19] 

[[*], [5, 3]] [on + press: displays "15"]
[[+], [15, 4]] [on eval press: displays "19"]

Lưu ý rằng biểu thức con * đang chờ xử lý [xếp chồng] được đánh giá khi nhấn dấu +. * toán tử liên kết chặt chẽ hơn +, vì vậy mã được đánh giá ngay trước khi toán tử + được đẩy. Khi nhấn nút +, trường nhập chứa 3. Nói chung, trường nhập luôn giữ toán hạng trước khi nhấn nút vận hành. Vì giá trị mục nhập văn bản được đẩy vào ngăn xếp toán hạng trước khi toán tử được áp dụng, nên chúng tôi phải bật kết quả trước khi hiển thị chúng sau khi nhấn "eval" hoặc ] [nếu không, kết quả sẽ được đẩy lên ngăn xếp hai lần]

2] "5 + 3 * 4 " [result = 17] 

[[+, *], [5, 3, 4]] [on eval press]
[[+], [5, 12]] [displays "17"]

Ở đây, + đang chờ xử lý được đánh giá khi nhấn nút *. vì * liên kết chặt chẽ hơn, chúng tôi cần hoãn + cho đến khi * có thể được đánh giá. Toán tử * được bật cho đến khi toán hạng bên phải của nó được nhìn thấy. Khi nhấn "eval", có hai toán tử để bật và áp dụng cho các mục trong ngăn xếp toán hạng

3] "5 + 3 + 4 " [result = 12]

[[+], [5, 3]] [on the second +]
[[+], [8, 4]] [on eval]

Đối với các chuỗi toán tử có cùng mức độ ưu tiên như chuỗi này, chúng tôi bật và đánh giá ngay lập tức khi chúng tôi quét từ trái sang phải, thay vì trì hoãn việc đánh giá. Điều này dẫn đến một đánh giá kết hợp trái, trong trường hợp không có dấu ngoặc đơn. 5+3+4 được đánh giá là [[5+3]+4]. Thứ tự không quan trọng đối với các hoạt động + và *

4] "1 + 3 * [ 1 + 3 * 4 ] " [result = 40] 

[[+, *, [, +, *], [1, 3, 1, 3, 4]] [on ]]
[[+, *, [, +], [1, 3, 1, 12]] [displays "13"]
[[+, *], [1, 3, 13]] [on eval]
[[+], [1, 39]]

Trong trường hợp này, tất cả các toán tử và toán hạng được xếp chồng lên nhau [hoãn lại] cho đến khi chúng ta nhấn nút ] ở cuối. Khi nhấn nút ], biểu thức con được đặt trong ngoặc đơn được bật lên và được đánh giá, đồng thời 13 được hiển thị trong trường mục nhập. Khi nhấn "eval", phần còn lại được đánh giá và kết quả cuối cùng [40] được hiển thị. Kết quả là toán hạng bên trái của toán tử khác. Trên thực tế, bất kỳ kết quả tạm thời nào cũng có thể được sử dụng lại. nếu chúng ta tiếp tục nhấn một nút toán tử mà không nhập toán hạng mới, nó sẽ được áp dụng lại cho kết quả của lần nhấn trước đó. Hình 18-12 cho thấy cách hai ngăn xếp nhìn ở mức cao nhất của chúng trong khi quét biểu thức trong dấu vết ví dụ trước. Toán tử trên cùng được áp dụng cho hai toán hạng trên cùng và kết quả được đẩy lùi cho toán tử bên dưới

5] "1 + 3 * [ 1 + 3 * 4 " [result = *ERROR*]

[[+, *, [, +, *], [1, 3, 1, 3, 4]] [on eval]
[[+, *, [, +], [1, 3, 1, 12]]
[[+, *, [], [1, 3, 13]]
[[+, *], [1, *ERROR*]]
[[+], [*ERROR*]]
[[+], [*ERROR*, *ERROR*]]
Hình 18-12. ngăn xếp đánh giá. 1 + 3 * [1 + 3 * 4]

Chuỗi này gây ra lỗi. PyCalc bình thường về xử lý lỗi. Nhiều lỗi không thể thực hiện được bằng chính thuật toán, nhưng những thứ như dấu ngoặc đơn chưa khớp vẫn gây khó khăn cho người đánh giá. Nhưng thay vì cố gắng phát hiện tất cả các trường hợp lỗi có thể xảy ra một cách rõ ràng, một câu lệnh try chung trong phương thức rút gọn được sử dụng để bắt tất cả chúng. lỗi diễn đạt, lỗi tên không xác định, lỗi cú pháp, v.v.

Toán hạng và kết quả tạm thời luôn được xếp chồng lên nhau dưới dạng chuỗi và mỗi toán tử được áp dụng bằng cách gọi eval. Khi xảy ra lỗi bên trong một biểu thức, toán hạng kết quả của *ERROR* được đẩy, điều này khiến cho tất cả các toán tử còn lại cũng không thành công trong eval. *ERROR* thấm vào đầu biểu thức. Cuối cùng, toán hạng cuối cùng của nó và được hiển thị trong trường nhập văn bản để cảnh báo bạn về lỗi

7. 2. 3 mã nguồn PyCalc

Ví dụ 18-16 chứa mô-đun nguồn PyCalc giúp những ý tưởng này hoạt động trong ngữ cảnh của GUI. Đây là cách triển khai một tệp [không tính các tiện ích được nhập và sử dụng lại]. Nghiên cứu nguồn để biết thêm chi tiết;

Ví dụ 18-16. PP2ELangMáy tínhmáy tính. py________số 8_______7. 2. 4 Sử dụng PyCalc làm thành phần

PyCalc phục vụ một chương trình độc lập trên máy tính để bàn của tôi, nhưng nó cũng hữu ích trong ngữ cảnh của các GUI khác. Giống như hầu hết các lớp GUI trong cuốn sách này, PyCalc có thể được tùy chỉnh bằng các phần mở rộng của lớp con hoặc được nhúng trong GUI lớn hơn với tệp đính kèm. Mô-đun trong Ví dụ 18-17 minh họa một cách để sử dụng lại lớp CalcGui của PyCalc bằng cách mở rộng và nhúng, tương tự như đã thực hiện đối với máy tính đơn giản trước đó

Ví dụ 18-17. PP2ELangCalculatorcalculator_test. py
##########################################################################
# test calculator use as an extended and embedded gui component;
##########################################################################

from Tkinter import *
from calculator import CalcGui
from PP2E.Dbase.TableBrowser.guitools import *

def calcContainer[parent=None]:
 frm = Frame[parent] 
 frm.pack[expand=YES, fill=BOTH]
 Label[frm, text=Calc Container].pack[side=TOP]
 CalcGui[frm]
 Label[frm, text=Calc Container].pack[side=BOTTOM]
 return frm

class calcSubclass[CalcGui]: 
 def makeWidgets[self, fg, bg, font]:
 Label[self, text=Calc Subclass].pack[side=TOP]
 Label[self, text=Calc Subclass].pack[side=BOTTOM]
 CalcGui.makeWidgets[self, fg, bg, font]
 #Label[self, text=Calc Subclass].pack[side=BOTTOM]

if __name__ == \__main__: 
 import sys
 if len[sys.argv] == 1: # % calculator_test.py
 root = Tk[ ] # run 3 calcs in same process
 CalcGui[Toplevel[ ]] # each in a new toplevel window
 calcContainer[Toplevel[ ]]
 calcSubclass[Toplevel[ ]] 
 Button[root, text=quit, command=root.quit].pack[ ]
 root.mainloop[ ]
 if len[sys.argv] == 2: # % calculator_testl.py -
 CalcGui[].mainloop[ ] # as a standalone window [default root]
 elif len[sys.argv] == 3: # % calculator_test.py - - 
 calcContainer[].mainloop[ ] # as an embedded component
 elif len[sys.argv] == 4: # % calculator_test.py - - - 
 calcSubclass[].mainloop[ ] # as a customized superclass

Hình 18-13 cho thấy kết quả của việc chạy tập lệnh này mà không có đối số dòng lệnh. Chúng tôi nhận được các phiên bản của lớp máy tính ban đầu, cộng với các lớp chứa và lớp con được xác định trong tập lệnh này, tất cả được đính kèm với các cửa sổ cấp cao nhất mới

Hình 18-13. Tập lệnh calculator_test. đính kèm và mở rộng

Hai cửa sổ bên phải này sử dụng lại mã PyCalc lõi đang chạy trong cửa sổ bên trái. Tất cả các cửa sổ này đều chạy trong cùng một quy trình [e. g. , thoát một cái là thoát tất cả], nhưng tất cả chúng đều hoạt động như những cửa sổ độc lập. Lưu ý rằng khi chạy ba máy tính trong cùng một quy trình như thế này, mỗi máy có không gian tên đánh giá biểu thức riêng biệt vì thuộc tính thể hiện của lớp chứ không phải biến cấp mô-đun toàn cầu. Do đó, các biến được đặt trong một máy tính chỉ được đặt trong máy tính đó và không ghi đè cài đặt được thực hiện trong các cửa sổ khác. Tương tự, mỗi máy tính có đối tượng trình quản lý ngăn xếp đánh giá riêng, sao cho các phép tính trong một cửa sổ hoàn toàn không xuất hiện hoặc tác động đến các cửa sổ khác

Tất nhiên, hai tiện ích mở rộng trong tập lệnh này là nhân tạo -- chúng chỉ thêm các nhãn ở trên cùng và dưới cùng của cửa sổ -- nhưng khái niệm này được áp dụng rộng rãi. Bạn có thể sử dụng lại lớp máy tính bằng cách gắn nó vào bất kỳ GUI nào cần máy tính và tùy ý tùy chỉnh nó với các lớp con. Đó là một tiện ích có thể tái sử dụng

7. 2. 5 Thêm các nút mới trong các thành phần mới

Một cách rõ ràng để sử dụng lại máy tính là thêm các nút tính năng biểu thức bổ sung -- căn bậc hai, nghịch đảo, lập phương, v.v. Bạn có thể nhập các thao tác như vậy trong cửa sổ bật lên dòng lệnh, nhưng các nút thuận tiện hơn một chút. Các tính năng như vậy cũng có thể được thêm vào chính việc triển khai máy tính chính; . Chẳng hạn, lớp trong Ví dụ 18-18 thêm một số nút bổ sung vào PyCalc bằng cách nhúng [i. e. , đính kèm] nó trong một thùng chứa

Ví dụ 18-18. PP2ELangCalculatorcalculator_plus_emb. py
from Tkinter import *
from calc0 import CalcGui

class Inner[CalcGui]: # extend gui
 def __init__[self]:
 CalcGui.__init__[self]
 Label[self, text=Calc Subclass].pack[ ] # add after
 Button[self, text=Quit, command=self.quit].pack[ ] # top implied
 
Inner[].mainloop[ ]
0

Vì PyCalc được mã hóa dưới dạng một lớp Python nên bạn luôn có thể đạt được hiệu quả tương tự bằng cách mở rộng PyCalc trong một lớp con mới thay vì nhúng nó, như trong Ví dụ 18-19

Ví dụ 18-19. PP2ELangCalculatorcalculator_plus_ext. py
from Tkinter import *
from calc0 import CalcGui

class Inner[CalcGui]: # extend gui
 def __init__[self]:
 CalcGui.__init__[self]
 Label[self, text=Calc Subclass].pack[ ] # add after
 Button[self, text=Quit, command=self.quit].pack[ ] # top implied
 
Inner[].mainloop[ ]
1

Lưu ý rằng các nút gọi lại này sử dụng 1. 0/x để buộc phép chia dấu phẩy động được sử dụng cho phép nghịch đảo [phép chia số nguyên cắt bớt phần còn lại] và bọc các giá trị trường mục nhập trong ngoặc đơn [để tránh các vấn đề ưu tiên]. Thay vào đó, họ có thể chuyển đổi văn bản mục nhập thành một số và thực hiện phép toán thực sự, nhưng Python thực hiện tất cả công việc một cách tự động khi các chuỗi biểu thức được chạy thô

Cũng lưu ý rằng các nút được thêm bởi các tập lệnh này chỉ hoạt động trên giá trị hiện tại trong trường mục nhập, ngay lập tức. Điều đó không hoàn toàn giống với các toán tử biểu thức được áp dụng với bộ đánh giá ngăn xếp [cần có các tùy chỉnh bổ sung để biến chúng thành toán tử đúng]. Tuy nhiên, các nút này chứng minh rằng các tập lệnh này được tạo ra -- chúng sử dụng PyCalc như một thành phần, cả bên ngoài và bên dưới

Cuối cùng, để kiểm tra cả hai lớp máy tính mở rộng, cũng như các tùy chọn cấu hình PyCalc, tập lệnh trong Ví dụ 18-20 đưa ra bốn cửa sổ máy tính riêng biệt [đây là tập lệnh do PyDemos điều hành]

Ví dụ 18-20. PP2ELangCalculatorcalculator_plusplus. py
from Tkinter import *
from calc0 import CalcGui

class Inner[CalcGui]: # extend gui
 def __init__[self]:
 CalcGui.__init__[self]
 Label[self, text=Calc Subclass].pack[ ] # add after
 Button[self, text=Quit, command=self.quit].pack[ ] # top implied
 
Inner[].mainloop[ ]
2

Hình 18-14 cho thấy kết quả -- bốn máy tính độc lập trong các cửa sổ cấp cao nhất trong cùng một quy trình. Các cửa sổ bên trái và bên phải đại diện cho việc sử dụng lại PyCalc chuyên biệt như một thành phần. Mặc dù có thể không rõ ràng trong cuốn sách này, nhưng cả bốn đều sử dụng các cách phối màu khác nhau;

Hình 18-14. Tập lệnh calculator_plusplus. mở rộng, nhúng và cấu hình

Như chúng ta đã biết trước đó, các máy tính này cũng có thể được chạy dưới dạng các quy trình độc lập bằng cách tạo ra các dòng lệnh với mô-đun launchmodes mà chúng ta đã gặp trong Chương 3. Trên thực tế, đó là cách các thanh trình khởi chạy Tiện ích và Trình diễn chạy máy tính, vì vậy hãy xem mã của chúng để biết thêm chi tiết

Bài Học 6 Vui Vẻ

Cuối cùng, đây là một khía cạnh ít hữu hình hơn nhưng quan trọng của lập trình Python. Một nhận xét chung của những người dùng mới là thật dễ dàng để "nói ý của bạn" bằng Python mà không bị sa lầy vào các cú pháp phức tạp hoặc các quy tắc khó hiểu. Đó là một ngôn ngữ thân thiện với lập trình viên. Trên thực tế, không có gì lạ khi các chương trình Python chạy trong lần thử đầu tiên

Như chúng ta đã thấy trong cuốn sách này, có một số yếu tố đằng sau sự khác biệt này -- thiếu khai báo, không có các bước biên dịch, cú pháp đơn giản, các đối tượng tích hợp hữu ích, v.v. Python được thiết kế đặc biệt để tối ưu hóa tốc độ phát triển [một ý tưởng sẽ được mở rộng trong Chương 21]. Đối với nhiều người dùng, kết quả cuối cùng là một ngôn ngữ phản hồi nhanh và biểu cảm rõ rệt, điều này thực sự có thể thú vị khi sử dụng

Chẳng hạn, các chương trình máy tính được hiển thị trước đó lần đầu tiên được kết hợp với nhau trong một buổi chiều, bắt đầu từ những mục tiêu mơ hồ, không đầy đủ. Không có giai đoạn phân tích, không có thiết kế chính thức và không có giai đoạn viết mã chính thức. Tôi đã gõ một số ý tưởng và chúng đã hoạt động. Hơn nữa, bản chất tương tác của Python cho phép tôi thử nghiệm những ý tưởng mới và nhận phản hồi ngay lập tức. Kể từ lần phát triển ban đầu, máy tính đã được hoàn thiện và mở rộng, nhưng cách triển khai cốt lõi vẫn không thay đổi

Đương nhiên, chế độ lập trình thoải mái như vậy không hoạt động cho mọi dự án. Đôi khi thiết kế phía trước nhiều hơn được bảo hành. Đối với các tác vụ đòi hỏi khắt khe hơn, Python có các cấu trúc mô-đun và các hệ thống hỗ trợ có thể được mở rộng bằng Python hoặc C. Và, một GUI máy tính đơn giản có thể không phải là thứ mà một số người gọi là phát triển phần mềm "nghiêm túc". Nhưng có lẽ đó cũng là một phần của vấn đề

Bạn có thể tạo một máy tính khoa học bằng Python không?

Chúng tôi đã tạo GUI Máy tính khoa học đơn giản bằng Python cho phép bạn thực hiện các phép tính đơn giản và phức tạp. Để triển khai GUI, chúng tôi sẽ sử dụng mô-đun Tkinter của Python.

Làm cách nào để thêm lịch sử vào máy tính bằng javascript?

Chúng tôi bắt đầu bằng cách gói mọi thứ trong một div với lớp container, sau đó chúng tôi phải div như những đứa trẻ hoạt động như hai cột. phía bên trái sẽ là máy tính và phía bên phải sẽ hiển thị Lịch sử. Đối với đầu vào và đầu ra, chúng tôi sử dụng phần tử đầu vào và chúng tôi vô hiệu hóa nó cho đầu ra

Chủ Đề