Hướng dẫn how to avoid global variables python - cách tránh biến toàn cục python

Thuật ngữ "Pythonic" không áp dụng cho chủ đề này-sử dụng các thế giới như thế này là thực tiễn kém trong bất kỳ ngôn ngữ lập trình và mô hình nào và không phải là một thứ gì đó cụ thể cho Python.

Từ khóa global là công cụ mà Python cung cấp cho bạn từ chối đóng gói và phá vỡ phạm vi tự nhiên của một biến. Đóng gói có nghĩa là mỗi thành phần của bạn là một đơn vị hợp lý, khép kín, nên hoạt động như một hộp đen và thực hiện một điều (lưu ý: điều này là khái niệm và có thể bao gồm nhiều bước, có thể không tầm thường) mà không có đột biến trạng thái toàn cầu hoặc tạo ra các tác dụng phụ. Lý do là mô -đun: nếu có sự cố xảy ra trong một chương trình (và nó sẽ), việc đóng gói mạnh mẽ giúp bạn rất dễ dàng xác định thành phần thất bại ở đâu.

Pacpsulsation làm cho mã dễ dàng hơn để tái cấu trúc, duy trì và mở rộng. Nếu bạn cần một thành phần để hoạt động khác nhau, sẽ dễ dàng loại bỏ nó hoặc điều chỉnh nó mà không có những sửa đổi này gây ra hiệu ứng domino của các thay đổi trên các thành phần khác trong hệ thống.

Các công cụ cơ bản để thực thi đóng gói bao gồm các lớp, chức năng, tham số và từ khóa return. Các ngôn ngữ thường cung cấp các mô-đun, không gian tên và đóng cửa cho hiệu ứng tương tự, nhưng mục tiêu cuối cùng là luôn giới hạn phạm vi và cho phép lập trình viên tạo ra các trừu tượng được kết hợp lỏng lẻo.

Các chức năng lấy đầu vào thông qua các tham số và tạo đầu ra thông qua các giá trị trả về. Bạn có thể gán giá trị trả về cho các biến trong phạm vi gọi. Bạn có thể nghĩ về các tham số là "núm" điều chỉnh hành vi của chức năng. Bên trong hàm, các biến chỉ là lưu trữ tạm thời được sử dụng bởi hàm cần thiết để tạo ra một giá trị trả về của nó sau đó biến mất.

Lý tưởng nhất, các chức năng được viết là tinh khiết và idempotent; Đó là, họ không sửa đổi trạng thái toàn cầu và tạo ra kết quả tương tự khi được gọi là nhiều lần. Python ít nghiêm ngặt hơn về điều này so với các ngôn ngữ khác và việc sử dụng các chức năng tại chỗ nhất định như sortrandom.shuffle là điều tự nhiên. Đây là những trường hợp ngoại lệ chứng minh quy tắc (và nếu bạn biết một chút về việc sắp xếp và xáo trộn, chúng có ý nghĩa trong các bối cảnh này do các thuật toán được sử dụng và nhu cầu về hiệu quả).

Một thuật toán tại chỗ không tinh khiết và không có ý kiến, nhưng nếu trạng thái mà nó sửa đổi bị giới hạn trong (các) tham số của nó và tài liệu và giá trị trả về của nó (thường là ____7) hỗ trợ điều này, hành vi này có thể dự đoán được và dễ hiểu.

Vậy tất cả những điều này trông như thế nào trong mã? Thật không may, ví dụ của bạn dường như bị giả mạo và không rõ ràng về mục đích/mục tiêu của nó, vì vậy không có cách nào trực tiếp để biến đổi nó làm cho những lợi thế của đóng gói rõ ràng.

Dưới đây là danh sách một số vấn đề trong các chức năng này ngoài việc sửa đổi trạng thái toàn cầu:

  • Sử dụng các chữ "yes""no" theo nghĩa đen thay vì ____ 10/________ 11 giá trị boolean.
  • Các giá trị mã hóa cứng trong các chức năng, làm cho chúng hoàn toàn một mục đích đơn lẻ (chúng cũng có thể được đưa vào).
  • def fmt_higher(name, n, cutoff=12):
        verb = "is" if n > cutoff else "isn't"
        return f"{name} {verb} higher than {cutoff}"
    
    if __name__ == "__main__":
        print(fmt_higher("alpha", 42))
        print(fmt_higher("beta", 6))
        print(fmt_higher("epsilon", 0))
        print(fmt_higher(name="delta", n=2, cutoff=-5))
    
    2ing trong các chức năng (xem các tác dụng phụ Ghi chú ở trên-yêu cầu trả về các giá trị và để phạm vi gọi điện in nếu chúng muốn làm như vậy).
  • Các tên biến chung như
    def fmt_higher(name, n, cutoff=12):
        verb = "is" if n > cutoff else "isn't"
        return f"{name} {verb} higher than {cutoff}"
    
    if __name__ == "__main__":
        print(fmt_higher("alpha", 42))
        print(fmt_higher("beta", 6))
        print(fmt_higher("epsilon", 0))
        print(fmt_higher(name="delta", n=2, cutoff=-5))
    
    3 (Tôi cho rằng điều này tương đương với ____ 14/________ 15 cho ví dụ, nhưng nó vẫn không biện minh cho lý do tồn tại của chúng, gây khó khăn cho việc sửa đổi làm ví dụ sư phạm).

Nhưng dù sao đây cũng là bức ảnh của tôi:

if __name__ == "__main__":
    alpha = 42
    beta = 6
    print("alpha %s higher than 12" % ("is" if alpha > 12 else "isn't"))
    print("beta %s higher than 12" % ("is" if beta > 12 else "isn't"))

Chúng ta có thể thấy không cần tất cả các chức năng-chỉ cần viết

def fmt_higher(name, n, cutoff=12):
    verb = "is" if n > cutoff else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))
6 bất cứ nơi nào bạn cần để so sánh và gọi
def fmt_higher(name, n, cutoff=12):
    verb = "is" if n > cutoff else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))
2 khi bạn cần in. Một nhược điểm của các chức năng là chúng có thể phục vụ để ẩn logic quan trọng, vì vậy nếu tên và "hợp đồng" của chúng (được xác định bởi tên, tài liệu và giá trị trả về) chức năng (chính bạn, nói chung).

Vì lợi ích của hình minh họa, hãy nói rằng bạn đang gọi định dạng này thường xuyên. Sau đó, có lý do để trừu tượng; Mã gọi sẽ trở nên cồng kềnh và lặp đi lặp lại. Bạn có thể di chuyển mã định dạng sang hàm trợ giúp và truyền bất kỳ dữ liệu động nào để bơm vào mẫu:

def fmt_higher(name, n, cutoff=12):
    verb = "is" if n > cutoff else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))

Chúng ta có thể tiến thêm một bước và giả vờ rằng

def fmt_higher(name, n, cutoff=12):
    verb = "is" if n > cutoff else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))
8 là một thử nghiệm phức tạp hơn nhiều với nhiều bước nhỏ sẽ vi phạm trách nhiệm đơn nếu để lại trong
def fmt_higher(name, n, cutoff=12):
    verb = "is" if n > cutoff else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))
9. Có thể thử nghiệm phức tạp được sử dụng ở nơi khác trong mã và có thể được khái quát hóa để hỗ trợ cả hai trường hợp sử dụng.

Trong tình huống này, bạn vẫn có thể sử dụng các tham số và trả về các giá trị thay vì global và thực hiện cùng một loại trừu tượng với vị ngữ như bạn đã làm với định dạng:

def complex_predicate(n, cutoff):
    # pretend this function is much more 
    # complex and/or used in many places...
    return n > cutoff

def fmt_higher(name, n, cutoff=12):
    verb = "is" if complex_predicate(n, cutoff) else "isn't"
    return f"{name} {verb} higher than {cutoff}"

if __name__ == "__main__":
    print(fmt_higher("alpha", 42))
    print(fmt_higher("beta", 6))
    print(fmt_higher("epsilon", 0))
    print(fmt_higher(name="delta", n=2, cutoff=-5))

Chỉ tóm tắt khi có đủ lý do để trừu tượng (mã gọi sẽ bị tắc nghẽn hoặc khi bạn lặp lại các khối mã tương tự nhiều lần là các quy tắc cổ điển). Và khi bạn làm trừu tượng, hãy làm đúng.

Bạn có nên tránh các biến toàn cầu Python?

Mặc dù trong nhiều hoặc hầu hết các biến ngôn ngữ lập trình khác được coi là toàn cầu nếu không được tuyên bố khác, Python liên quan đến các biến theo cách khác. Họ là địa phương, nếu không tuyên bố. Lý do lái xe đằng sau phương pháp này là các biến toàn cầu nói chung là thực tiễn xấu và nên tránh.global variables are generally bad practice and should be avoided.

Làm thế nào chúng ta có thể tránh các biến toàn cầu?

Cách đơn giản nhất để tránh toàn cầu tất cả cùng nhau là chỉ cần chuyển các biến của bạn bằng các đối số chức năng. Như bạn có thể thấy, mảng $ ProductData từ bộ điều khiển (thông qua yêu cầu HTTP) đi qua các lớp khác nhau: Bộ điều khiển nhận được yêu cầu HTTP. Các tham số được chuyển đến mô hình.pass your variables using function arguments. As you can see, the $productData array from the controller (via HTTP request) goes through different layer: The controller receives the HTTP request. The parameters are passed to the model.

Làm thế nào các tham số có thể được sử dụng để tránh việc sử dụng các biến toàn cầu?

Tham số truyền - Cho phép các giá trị của các biến cục bộ trong chương trình chính được chuyển sang chương trình con mà không cần sử dụng các biến toàn cầu. Giá trị của các biến này (hoặc một bản sao giá trị của các biến này) được truyền dưới dạng tham số đến và từ các chương trình phụ khi cần thiết. - allows the values of local variables within the main program to be passed to sub-programs without the need to use global variables. The value of these variables (or a copy of the value of these variables) is passed as a parameter to and from sub-programs as necessary.

Tôi có thể sử dụng gì thay vì biến toàn cầu?

Trong một kịch bản, nơi bạn cần một điểm truy cập toàn cầu trung tâm trên cơ sở mã, Singletons là một giải pháp thay thế tốt cho các biến toàn cầu.Chúng ta có thể gọi một singleton là một lớp toàn cầu được khởi tạo một cách lười biếng, rất hữu ích khi bạn có các đối tượng lớn - phân bổ bộ nhớ có thể được hoãn lại cho đến khi nó thực sự cần thiết.singletons are a good alternative for global variables. We can call a singleton as a lazily initialized global class which is useful when you have large objects — memory allocation can be deferred till when it's actually needed.