8

Tôi muốn các hàm khác nhau có thể thực thi chỉ khi người dùng đã đăng nhập có cấp quyền cần thiết.trang trí để đặt thuộc tính của hàm

Để làm cho cuộc sống của tôi phức tạp hơn, đơn giản là tôi muốn sử dụng trang trí. Dưới đây tôi cho rằng thiết lập thuộc tính permission trên các chức năng 'được trang trí' - như được hiển thị bên dưới.

def permission(permission_required): 
    def wrapper(func): 
     def inner(*args, **kwargs): 
      setattr(func, 'permission_required', permission_required) 
      return func(*args, **kwargs) 
     return inner 
    return wrapper 

@permission('user') 
def do_x(arg1, arg2): 

    ... 

@permission('admin') 
def do_y(arg1, arg2): 
    ... 

Nhưng khi tôi làm:

fn = do_x 
if logged_in_user.access_level == fn.permission_required: 
    ... 

tôi nhận được một lỗi 'function' object has no attribute 'permission_required'

tôi thiếu gì?

+1

Lưu ý: Tôi chắc chắn bạn muốn sử dụng ['functools.wraps'] (http://docs.python.org/2/library/functools.html#functools.wraps) đây. Không trực tiếp giải quyết vấn đề của bạn, nhưng vì không thể gỡ lỗi loại mã này khi mọi hàm kết thúc có tên 'inner', lấy' (* args, ** kwargs) ',' checking' đến nguồn sai, vv – abarnert

Trả lời

14

Bạn đang đặt thuộc tính trong hàm bên trong (trình bao bọc). Bạn không cần phải có chức năng bao bọc ở tất cả:

def permission(permission_required): 
    def decorator(func): 
     func.permission_required = permission_required 
     return func 
    return decorator 

trang trí của bạn cần phải quay trở lại một cái gì đó rằng sẽ thay thế chức năng ban đầu. Bản thân hàm ban đầu (với thuộc tính được thêm vào) sẽ làm tốt cho điều đó, bởi vì tất cả những gì bạn muốn làm là thêm thuộc tính vào nó.

Nếu bạn vẫn cần một wrapper, sau đó thiết lập các thuộc tính về chức năng wrapper thay vì:

def permission(permission_required): 
    def decorator(func): 
     def wrapper(*args, **kwargs): 
      # only use a wrapper if you need extra code to be run here 
      return func(*args, **kwargs) 
     wrapper.permission_required = permission_required 
     return wrapper 
    return decorator 

Sau khi tất cả, bạn đang thay thế các chức năng được bao bọc bởi các wrapper được trả về bởi các trang trí, vì vậy đó là đối tượng bạn sẽ tìm thuộc tính trên đó.

+0

Tôi cần trình bao bọc để cho phép đối số trong hàm được trang trí. Tôi đã sử dụng mã của bạn và nó hoạt động tốt - nhưng khi tôi thêm trình bao bọc cho các đối số thì lỗi đã xuất hiện trở lại. – rikAtee

+1

@rikAtee: Bạn không cần trình bao bọc để cho phép đối số trong hàm được trang trí. Ví dụ đầu tiên chỉ sửa đổi và trả về hàm; nó vẫn có cùng một đối số chính xác mà nó đã làm trước khi được trang trí. – abarnert

+0

@rikAtee: Thật vậy, trình bao bọc là * không * bắt buộc nếu tất cả những gì bạn làm là đặt thuộc tính. Chỉ thêm trình bao bọc nếu có nhu cầu về trình bao bọc (ví dụ: thêm mã phụ để hoạt động trên các đối số hoặc giá trị trả lại hoặc thực hiện thêm các chức năng khi hàm được gọi). –

1

trang trí của bạn nên quay trở lại một chức năng mà có thể thay thế do_x hoặc do_y, không quay trở lại thực hiện kết quả của do_x hoặc do_y Bạn có thể modity bạn trang trí như sau:

def permission(permission_required): 
    def wrapper(func): 
     def inner(): 
      setattr(func, 'permission_required', permission_required) 
      return func 
     return inner() 
    return wrapper 

Tất nhiên, bạn có một giải pháp ngắn gọn :

def permission(permission_required): 
    def wrapper(func): 
     setattr(func, 'permission_required', permission_required) 
     return func 
    return wrapper 
+1

Chức năng bên trong của bạn không * không có gì *, vì vậy bạn đang thay thế bản gốc bằng một hàm không có gì hơn là đặt thuộc tính trên hàm được bọc, làm cho nó * vô ích *. –

Các vấn đề liên quan