Helpex - Trao đổi & giúp đỡ Đăng nhập
19

Tôi đang gặp một vấn đề rất kỳ lạ trong trình trang trí Python 3.

Nếu tôi làm điều này:

def rounds(nr_of_rounds):
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            return nr_of_rounds
        return inner
    return wrapper

nó hoạt động tốt. Tuy nhiên, nếu tôi làm điều này:

def rounds(nr_of_rounds):
    def wrapper(func):
        @wraps(func)
        def inner(*args, **kwargs):
            lst = []
            while nr_of_rounds > 0:
                lst.append(func(*args, **kwargs))
                nr_of_rounds -= 1
            return max(lst)
        return inner
    return wrapper

Tôi có:

while nr_of_rounds > 0:
UnboundLocalError: local variable 'nr_of_rounds' referenced before assignment

Nói cách khác, tôi có thể sử dụng nr_of_roundstrong hàm bên trong nếu tôi sử dụng nó để trả về, nhưng tôi không thể làm gì khác với nó. Tại sao vậy?

19 hữu ích 1 bình luận 2.5k xem chia sẻ
16

nr_of_roundsđược chọn bằng cách đóng , bạn có thể coi nó như một biến "chỉ đọc". Nếu bạn muốn ghi vào nó (ví dụ: để giảm nó), bạn cần phải nói rõ ràng với python - Trong trường hợp này, nonlocaltừ khóa python3.x sẽ hoạt động.

Như một lời giải thích ngắn gọn, những gì Cpython làm khi gặp định nghĩa hàm là nó xem mã và quyết định xem tất cả các biến là cục bộ hay không cục bộ . Các biến cục bộ (theo mặc định) là bất kỳ thứ gì xuất hiện ở phía bên trái của câu lệnh gán, các biến vòng lặp và các đối số đầu vào. Mọi tên khác đều không thuộc địa phương. Điều này cho phép một số tối ưu hóa gọn gàng 1 . Để sử dụng biến không phải cục bộ giống như cách bạn làm với biến cục bộ, bạn cần nói rõ ràng với python thông qua câu lệnh globalhoặc nonlocal. Khi trăn gặp một cái gì đó mà nó nghĩ rằng nên là một địa phương, nhưng thực sự không phải là, bạn nhận được một UnboundLocalError.

1 Trình tạo bytecode Cpython biến các tên cục bộ thành các chỉ số trong một mảng để tra cứu tên cục bộ (lệnh bytecode LOAD_FAST) nhanh như lập chỉ mục một mảng cộng với chi phí bytecode thông thường.

16 hữu ích 5 bình luận chia sẻ
0

Hiện tại, không có cách nào để làm điều tương tự đối với các biến trong phạm vi hàm bao quanh, nhưng Python 3 giới thiệu một từ khóa mới, "nonlocal" sẽ hoạt động theo cách tương tự như toàn cục, nhưng đối với phạm vi hàm lồng nhau.
vì vậy trong trường hợp của bạn chỉ cần sử dụng như:
def inner(*args, **kwargs): nonlocal nr_of_rounds lst = [] while nr_of_rounds > 0: lst.append(func(*args, **kwargs)) nr_of_rounds -= 1 return max(lst) return inner
Để biết thêm thông tin Mô tả ngắn gọn về Quy tắc xác định phạm vi?

0 hữu ích 0 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ python python-3.x decorator python-decorators , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading