2016-04-05 18 views
5

Tôi đang tìm hiểu một chút về các trang trí từ một hướng dẫn tuyệt vời trên thecodeship nhưng đã thấy mình khá bối rối bởi một ví dụ.Ví dụ về trang trí Python

Đầu tiên là một ví dụ đơn giản, sau đó giải thích được đưa ra cho trang trí là gì.

def p_decorate(func): 
    def func_wrapper(name): 
     return "<p>{0}</p>".format(func(name)) 
    return func_wrapper 

def get_text(name): 
    return "lorem ipsum, {0} dolor sit amet".format(name) 

my_get_text = p_decorate(get_text) 

print my_get_text("John") 

Điều này có ý nghĩa với tôi. Trình trang trí chỉ đơn giản là một trình bao bọc cho một hàm. Và trong lời giải thích này, anh ta nói một người trang trí là một hàm có chức năng khác như một đối số, tạo ra một hàm mới và trả về hàm được sinh ra để sử dụng ở bất cứ đâu.

Và bây giờ là tương đương với các mã trên là:

def p_decorate(func): 
    def func_wrapper(name): 
     return "<p>{0}</p>".format(func(name)) 
    return func_wrapper 

@p_decorate 
def get_text(name): 
    return "lorem ipsum, {0} dolor sit amet".format(name) 

print get_text("John") 

Tôi tin rằng tôi hiểu được cách một trang trí được khởi tạo khi đưa ra không có đối số. Đúng nếu tôi đã sai lầm.

  • Các trang trí theo mặc định đi trong hàm get_text và vì p_decorate trả về một chức năng func_wrapper, chúng tôi kết thúc với báo cáo kết quả thực get_text = func_wrapper.

Điều quan trọng đối với tôi là khối mã tương đương đầu tiên, bởi vì tôi thấy và hiểu cách trang trí hoạt động.

gì rất nhiều bối rối cho tôi là đoạn mã sau:

def tags(tag_name): 
    def tags_decorator(func): 
     def func_wrapper(name): 
      return "<{0}>{1}</{0}>".format(tag_name, func(name)) 
     return func_wrapper 
    return tags_decorator 

@tags("p") 
def get_text(name): 
    return "Hello "+name 

print get_text("John") 

Một lần nữa, chính xác cho tôi nếu tôi sai, nhưng đây là sự hiểu biết của tôi.

  • Bộ trang trí chấp nhận chuỗi thẻ "p" thay vì tên chức năng mặc định. Và đến lượt hàm tags_decorator giả định rằng tham số sẽ được chuyển vào là hàm đang được trang trí, get_text.

Có thể hữu ích khi thấy khối mã tương đương trong biểu mẫu "không trang trí" nhưng tôi dường như không bao quanh đầu những gì sẽ bắt đầu trông như thế nào. Tôi cũng không hiểu tại sao tags_decoratorfunc_wrapper đều được trả lại. Mục đích của việc trả về hai hàm khác nhau là gì nếu một người trang trí chỉ cần trả về 1 hàm để bọc get_text.

Như một lưu ý phụ, nó thực sự đi kèm với những điều sau đây.

  • Khối này có thể được đơn giản hóa thành thứ gì đó ít hơn một bộ 3 chức năng không?
  • Người trang trí có thể chấp nhận nhiều hơn 1 đối số để đơn giản hóa mã không?

Trả lời

7

Trong giới hạn, mọi thứ sau @ được thực hiện để sản xuất trang trí.Trong ví dụ đầu tiên của bạn, những gì sau sau khi @ chỉ là một cái tên:

@p_decorate 

nên Python nhìn lên p_decorate và gọi nó với chức năng trang trí như một cuộc tranh cãi:

get_text = p_decorate(get_text) 

(quá đơn giản hóa một chút, get_text ban đầu không bị ràng buộc với hàm ban đầu, nhưng bạn đã có ý chính).

Trong ví dụ thứ hai của bạn, khái niệm trang trí là một chút tham gia nhiều hơn, nó bao gồm một cuộc gọi:

@tags("p") 

nên Python sử dụng tags("p") để tìm trang trí. Cuối cùng đây là những gì sau đó được thực hiện:

get_text = tags("p")(get_text) 

Các đầu ra của tags("p") là trang trí ở đây! Tôi tự gọi hàm tags là một trang trí nhà máy, nó tạo ra một trình trang trí khi được gọi. Khi bạn gọi số tags(), số này trả về tags_decorator(). Đó là bất động sản trang trí ở đây.

Bạn thay vì có thể loại bỏ các chức năng trang trí và hardcode giá trị "p" và sử dụng trực tiếp:

def tags_decorator_p(func): 
    def func_wrapper(name): 
     return "<{0}>{1}</{0}>".format("p", func(name)) 
    return func_wrapper 

@tags_decorator_p 
def get_text(name): 
    # ... 

nhưng sau đó bạn sẽ phải tạo trang trí riêng biệt cho mỗi giá trị có thể có của các lập luận để tags(). Đó là giá trị của một nhà máy trang trí, bạn có thể thêm các tham số cho trang trí và thay đổi cách chức năng của bạn được trang trí.

Trình trang trí nhà máy có thể thực hiện bất kỳ số lượng đối số nào; nó chỉ là một hàm bạn gọi để tạo ra một trang trí. Người trang trí chính nó chỉ có thể chấp nhận một đối số, chức năng để trang trí.

Tôi đã nói, trong giới hạn khi bắt đầu câu trả lời của tôi vì một lý do; cú pháp cho biểu thức sau @ chỉ cho phép tên chấm chấm (foo.bar.baz, vì vậy hãy truy cập thuộc tính) và gọi ((arg1, arg2, keyword=arg3)). Xem reference documentation. Bản gốc PEP 318 tiểu bang:

Tuyên bố trang trí được giới hạn trong những gì nó có thể chấp nhận - biểu thức tùy ý sẽ không hoạt động. Guido ưa thích điều này vì cảm giác ruột [17].

+0

Cảm ơn bạn. Và tôi đã chỉnh sửa ngắn sau câu trả lời của bạn. Tại sao chính xác các hàm này trả về 2 hàm và không phải 1? – Max

+1

@Max: xem chỉnh sửa mới nhất của tôi. Một là trang trí (được sản xuất bởi nhà máy trang trí), khác là trình bao bọc thay thế chức năng gốc, kết quả của trang trí. –

+0

Tôi hiểu bây giờ, mục đích của 2 cuộc gọi hàm. Tôi có thể làm cho một trang trí cụ thể với các nhà máy trang trí để tiếp tục xác định wrapper cuối cùng của tôi. – Max