2017-01-23 18 views
6

Tôi mới sử dụng Python và trang trí, vì vậy xin lỗi nếu điều này có vẻ là một câu hỏi tầm thường.Sử dụng vòng lặp để trang trí nhiều chức năng được nhập trong Python

Tôi cố gắng để áp dụng trang trí với nhiều chức năng nhập khẩu dùng một vòng lặp bằng Python như hiển thị dưới đây

from random import random, randint, choice 

def our_decorator(func): 
    def function_wrapper(*args, **kwargs): 
     print("Before calling " + func.__name__) 
     res = func(*args, **kwargs) 
     print(res) 
     print("After calling " + func.__name__) 
    return function_wrapper 

for f in [random, randint, choice]: 
    f = our_decorator(f) 

random() 
randint(3, 8) 
choice([4, 5, 6]) 

Lý tưởng nhất, tôi mong đợi đầu ra được ở dạng này:

Before calling random 
<random_value> 
After calling random 
Before calling randint 
<random_integer> 
After calling randint 
Before calling choice 
<random_choice> 
After calling choice 

Nhưng, Tôi chỉ nhận được kết quả của chức năng lựa chọn là đầu ra.

<random_choice among 4,5 6> 

Bộ trang trí không được áp dụng cho bất kỳ chức năng nào và trông giống như cuộc gọi ngẫu nhiên() và randint (3,8) không được thực thi.

Tôi muốn biết, điều gì đang xảy ra ở đây và có thể làm gì để trang trí nhiều chức năng được nhập bằng cách sử dụng vòng lặp?

Thanks for the help

Trả lời

5

Bạn đang trang trí các chức năng và sau đó gắn kết tên f cho từng người trong số họ lần lượt. Vì vậy, sau vòng lặp, f sẽ bằng với chức năng được trang trí cuối cùng. Tên gốc cho các chức năng ban đầu không bị ảnh hưởng.

Bạn sẽ phải làm việc với những cái tên, một cái gì đó giống như

gl = globals() 
for f_name in ['random', 'randint', 'choice']: 
    gl[f_name] = our_decorator(gl[f_name]) 

Nhưng tôi sẽ nhiều thích chỉ áp dụng trang trí cho mỗi chức năng lần lượt bằng tay.

2

Bạn có thể làm điều này bằng cách thiết lập nó cho gói random như:

import random 

for f in ['random','randint','choice']: 
    setattr(random,f,our_decorator(getattr(random,f))) 

Ở đây bạn nên thiết lập các "thuộc tính" của gói random. Cũng lưu ý rằng trong vòng lặp for của bạn, bạn cung cấp chuỗi.

và sau đó gọi với:

random.random() 
random.randint(3, 8) 
random.choice([4, 5, 6]) 

Tuy nhiên, điều này không trông rất thanh lịch. Trình trang trí thường được áp dụng bằng cách sử dụng @ -syntax trên chính hàm đó.

3

Tôi đồng ý với Remco & Willem sử dụng cú pháp @ theo cách thông thường sẽ tốt hơn, mặc dù cách tiếp cận của Willem về sửa đổi các thuộc tính của mô-đun random được nhập có lẽ tốt hơn so với xử lý người globals().Nhưng đây là một cách khác:

from random import random, randint, choice 

def our_decorator(func): 
    def function_wrapper(*args, **kwargs): 
     print("Before calling " + func.__name__) 
     res = func(*args, **kwargs) 
     print(res) 
     print("After calling " + func.__name__) 
    return function_wrapper 

random, randint, choice = [our_decorator(f) for f in (random, randint, choice)] 

random() 
randint(3, 8) 
choice([4, 5, 6]) 

đầu ra

Before calling random 
0.8171920550436872 
After calling random 
Before calling randint 
8 
After calling randint 
Before calling choice 
4 
After calling choice 

Trong những ý kiến, RemcoGerlich chỉ ra rằng kỹ thuật trang trí các thuộc tính của mô-đun random Willem Van Onsem có nghĩa rằng bất kỳ khác nhập khẩu các mô-đun sử dụng các chức năng được trang trí trong random cũng sẽ bị ảnh hưởng. Điều đó hoàn toàn chính xác nếu mô-đun kia sử dụng câu lệnh chuẩn import random. Tôi đoán rằng trong một số trường hợp, hành vi thực sự có thể được mong muốn.

Tuy nhiên, có một cách mà nếu bạn có quyền kiểm soát mã trong mô-đun khác. Nếu mô-đun kia sử dụng biểu mẫu from random import choice, thì mô-đun sẽ nhận phiên bản chưa được trang bị của choice. Đây là một bản demo ngắn.

dectest.py

#!/usr/bin/env python3 

from random import choice 

def test(seq): 
    print('In test') 
    return choice(seq) 

import random 
import dectest 

def our_decorator(func): 
    def function_wrapper(*args, **kwargs): 
     print("Before calling " + func.__name__) 
     res = func(*args, **kwargs) 
     print(res) 
     print("After calling " + func.__name__) 
     return res 
    return function_wrapper 

f = 'choice' 
setattr(random, f, our_decorator(getattr(random, f))) 

a = [4, 5, 6, 7] 
print(random.choice(a)) 

print('dectest') 
print(dectest.test(a)) 

điển hình đầu ra

Before calling choice 
6 
After calling choice 
6 
dectest 
In test 
7 

Nếu dectest.py trông như thế này:

import random 

def test(seq): 
    print('In test') 
    return random.choice(seq) 

sau đó chúng tôi nhận hành vi mà Remco đề cập:

Before calling choice 
5 
After calling choice 
5 
dectest 
In test 
Before calling choice 
4 
After calling choice 
4 
+0

Nhưng thực sự thay đổi các chức năng trong module ngẫu nhiên cũng thay đổi các thư viện khác điều đó xảy ra để sử dụng mô-đun đó, điều đó có thể nguy hiểm. Globals() là bất thường và là dấu hiệu của việc làm những thứ có lẽ không cần thiết, nhưng nó không đặc biệt nguy hiểm. – RemcoGerlich

+0

Theo tôi biết điều này không thay đổi chức năng * trên toàn cầu *: bạn chỉ đặt các chức năng khác nhau cho tệp hiện tại. –

+0

@WillemVanOnsem: có điều này, nhưng giải pháp của bạn thực sự thay đổi các chức năng trong mô-đun ngẫu nhiên, mã khác cũng sẽ thấy nó. – RemcoGerlich

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