<!DOCTYPE html>
    <html lang="vi" xmlns="http://www.w3.org/1999/xhtml" prefix="og: http://ogp.me/ns#">
    <head>
<title>Decorator trong Python</title>
<meta name="description" content="Decorator trong Python - Savefile - Tin Tức - https&#x3A;&#x002F;&#x002F;www.nguoicodonvn2008.info&#x002F;vi&#x002F;news&#x002F;savefile&#x002F;kien-thuc-may-tinh&#x002F;decorator-trong-python-521.html">
<meta name="author" content=".: Nguoicodonvn2008.info - Cõi lòng người cô đơn :.">
<meta name="copyright" content=".: Nguoicodonvn2008.info - Cõi lòng người cô đơn :. [admin@nguoicodonvn2008.info]">
<meta name="robots" content="index, archive, follow, noodp">
<meta name="googlebot" content="index,archive,follow,noodp">
<meta name="msnbot" content="all,index,follow">
<meta name="generator" content="NukeViet v4.5">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta property="og:title" content="Decorator trong Python">
<meta property="og:type" content="website">
<meta property="og:description" content="Savefile - Tin Tức - https&#x3A;&#x002F;&#x002F;www.nguoicodonvn2008.info&#x002F;vi&#x002F;news&#x002F;savefile&#x002F;kien-thuc-may-tinh&#x002F;decorator-trong-python-521.html">
<meta property="og:site_name" content=".&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;.">
<meta property="og:url" content="https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/decorator-trong-python-521.html">
<link rel="shortcut icon" href="https://www.nguoicodonvn2008.info/favicon.ico">
<link rel="canonical" href="https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/decorator-trong-python-521.html">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/" title="Tin Tức" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/karaoke-dual/" title="Tin Tức - Karaoke Dual" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/nhac-tre/" title="Tin Tức - Nhạc trẻ" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/tru-tinh/" title="Tin Tức - Trữ tình" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/nuoc-ngoai/" title="Tin Tức - Nước ngoài" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/remix/" title="Tin Tức - Remix" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/tam-su-tinh-yeu/" title="Tin Tức - Tâm sự tình yêu" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/tho-suu-tam/" title="Tin Tức - Thơ sưu tầm" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/cuoc-song/" title="Tin Tức - Cuộc sống" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/phan-mem/" title="Tin Tức - Phần mềm" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/kien-thuc-may-tinh/" title="Tin Tức - Kiến thức máy tính" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/hoc-tap/" title="Tin Tức - Học tập" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/tai-lieu/" title="Tin Tức - Tài liệu" type="application/rss+xml">
<link rel="alternate" href="https://www.nguoicodonvn2008.info/vi/news/rss/de-thi/" title="Tin Tức - Đề thi" type="application/rss+xml">
<link rel="preload" as="style" href="https://www.nguoicodonvn2008.info/assets/css/font-awesome.min.css" type="text/css">
<link rel="preload" as="style" href="https://www.nguoicodonvn2008.info/themes/default/css/bootstrap.non-responsive.css" type="text/css">
<link rel="preload" as="style" href="https://www.nguoicodonvn2008.info/themes/default/css/style.css" type="text/css">
<link rel="preload" as="style" href="https://www.nguoicodonvn2008.info/themes/default/css/style.non-responsive.css" type="text/css">
<link rel="preload" as="style" href="https://www.nguoicodonvn2008.info/themes/default/css/news.css" type="text/css">
<link rel="preload" as="style" href="https://www.nguoicodonvn2008.info/themes/default/css/custom.css" type="text/css">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/assets/js/jquery/jquery.min.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/assets/js/language/vi.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/assets/js/DOMPurify/purify3.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/assets/js/global.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/assets/js/site.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/themes/default/js/news.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/themes/default/js/main.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/themes/default/js/custom.js" type="text/javascript">
<link rel="preload" as="script" href="https://www.nguoicodonvn2008.info/themes/default/js/bootstrap.min.js" type="text/javascript">
<link rel="stylesheet" href="https://www.nguoicodonvn2008.info/assets/css/font-awesome.min.css">
<link rel="stylesheet" href="https://www.nguoicodonvn2008.info/themes/default/css/bootstrap.non-responsive.css">
<link rel="stylesheet" href="https://www.nguoicodonvn2008.info/themes/default/css/style.css">
<link rel="stylesheet" href="https://www.nguoicodonvn2008.info/themes/default/css/style.non-responsive.css">
<link rel="StyleSheet" href="https://www.nguoicodonvn2008.info/themes/default/css/news.css">
<link rel="stylesheet" href="https://www.nguoicodonvn2008.info/themes/default/css/custom.css">
<style type="text/css">
	body{background: #fff;}
</style>
    </head>
    <body>
<div id="print">
	<div id="hd_print">
		<h2 class="pull-left">.&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;.</h2>
		<p class="pull-right"><a title=".&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;." href="https://www.nguoicodonvn2008.info/">https://www.nguoicodonvn2008.info</a></p>
	</div>
	<div class="clear"></div>
	<hr />
	<div id="content">
		<h1>Decorator trong Python</h1>
		<ul class="list-inline">
			<li>Thứ bảy - 20/07/2019 22:15</li>
			<li class="hidden-print txtrequired"><em class="fa fa-print">&nbsp;</em><a title="In ra" href="javascript:;" onclick="window.print()">In ra</a></li>
			<li class="hidden-print txtrequired"><em class="fa fa-power-off">&nbsp;</em><a title="Đóng cửa sổ này" href="javascript:;" onclick="window.close()">Đóng cửa sổ này</a></li>
		</ul>
		<div class="clear"></div>
		<div id="hometext">
		</div>
		<div id="bodytext" class="clearfix">
			<p style="text-align: justify;"><strong>Decorator</strong>&nbsp;được sử dụng tương đối nhiều trong&nbsp;Python. Ở bài viết này, Quantrimang.com sẽ cùng bạn tìm hiểu làm thế nào để tạo ra một Decorator và lý do tại sao bạn nên sử dụng nó. Hãy cùng đi tìm lời giải đáp!&nbsp;</p>

<h2 style="text-align: justify;">Decorator trong Python là gì?</h2>

<p style="text-align: justify;">Python có một tính năng khá thú vị gọi là decorator. Decorator là một hàm&nbsp;<strong>nhận tham số đầu vào là một hàm khác và mở rộng tính năng cho hàm đó mà không thay đổi nội dung của nó.</strong></p>

<p style="text-align: justify;">Đây cũng được gọi là metaprogramming - siêu lập trình, hiểu đơn giản là &quot;Code sinh ra code&quot;, nghĩa là mình viết một chương trình và chương trình này sẽ sinh ra, điều khiển các chương trình khác hoặc làm một phần công việc ngay tại thời điểm biên dịch.&nbsp;</p>

<h2 style="text-align: justify;">Điều kiện để có Decorator</h2>

<p style="text-align: justify;">Để hiểu về decorator, trước tiên bạn cần xem lại một vài điều cơ bản trong Python.</p>

<p style="text-align: justify;"><strong>Hàm</strong>&nbsp;là một khái niệm rất cơ bản trong lập trình nói chung. Tuy nhiên, trong Python,&nbsp;<strong>hàm cũng là đối tượng.</strong>&nbsp;Các tên hàm mà chúng ta khai báo chỉ đơn giản là định danh ràng buộc với các đối tượng này. Một đối tượng hàm cũng có thể được liên kết cùng với nhiều tên khác nhau. Ví dụ:</p>

<pre id="pre0">
<code>def first(msg):
     print(msg)    
 first(&quot;Hello&quot;)
 second = first
 second(&quot;Hello&quot;)</code></pre>

<p style="text-align: justify;">Khi bạn chạy code, hàm&nbsp;<code>first</code>&nbsp;và&nbsp;<code>second</code>&nbsp;đều trả về cùng một output. Ở đây,&nbsp;<code>first</code>và&nbsp;<code>second</code>&nbsp;đề cập đến cùng một đối tượng hàm.</p>

<p style="text-align: justify;">Hãy theo dõi tiếp, các hàm có thể được truyền dưới dạng tham số cho một hàm khác (tương tự như&nbsp;<em>map, filter</em>&nbsp;và&nbsp;<em>reduce</em>&nbsp;trong Python).</p>

<p style="text-align: justify;">Những hàm lấy hàm khác làm tham số đầu vào được gọi là&nbsp;<strong>hàm bậc cao</strong>&nbsp;(higher-order functions). Ví dụ như này:</p>

<pre id="pre1">
<code>def inc(x):
     return x + 1
 def dec(x):
     return x - 1
 def operate(func, x):
     result = func(x)
     return result</code></pre>

<p style="text-align: justify;">Chúng ta gọi hàm như sau.</p>

<pre id="pre2">
<code>&gt;&gt;&gt; operate(inc,3)
 4
 &gt;&gt;&gt; operate(dec,3)
 2</code></pre>

<p style="text-align: justify;">Hơn nữa, một hàm có thể trả về kết quả một hàm khác.</p>

<pre id="pre3">
<code>def is_called():
     def is_returned():
         print(&quot;Hello&quot;)
     return is_returned
 new = is_called()
 #Outputs &quot;Hello&quot;
 new()</code></pre>

<p style="text-align: justify;">Ở đây,&nbsp;<em>is_returned()</em>&nbsp;là một hàm lồng nhau, hàm này sẽ được truy cập và trả về kết quả mỗi khi ta gọi hàm&nbsp;<em>is_called().</em></p>

<p style="text-align: justify;">Để rõ hơn, bạn có thể tham khảo thêm bài học&nbsp;<a href="https://quantrimang.com/cach-su-dung-closure-trong-python-165316" title="Cách sử dụng Closure trong Python">Cách sử dụng Closure trong Python</a></p>

<p style="text-align: justify;"><strong>Quay trở lại với Decorator</strong>, hiểu một cách cơ bản nhất, Decorator là một hàm có thể nhận các hàm khác, cho phép bạn chạy một số đoạn code trước hoặc sau hàm chính mà không thay đổi kết quả.</p>

<pre id="pre4">
<code>def make_pretty(func):
     def inner():
         print(&quot;I got decorated&quot;)
         func()
     return inner
 def ordinary():
     print(&quot;I am ordinary&quot;)</code></pre>

<p style="text-align: justify;">Chạy code trong Python shell:</p>

<pre id="pre5">
<code>&gt;&gt;&gt; ordinary()
 I am ordinary
 &gt;&gt;&gt; # Thử hàm decorate trong hàm ordinary
 &gt;&gt;&gt; pretty = make_pretty(ordinary)
 &gt;&gt;&gt; pretty()
 I got decorated
 I am ordinary</code></pre>

<p style="text-align: justify;">Trong ví dụ trên,&nbsp;<em>make_pretty()</em>&nbsp;là một decorator. Khi ta gọi</p>

<pre id="pre6">
<code>pretty = make_pretty(ordinary)
 </code></pre>

<p style="text-align: justify;">thì hàm&nbsp;<em>ordinary()</em>&nbsp;được decorator truyền vào làm tham số và hàm trả về tên là&nbsp;<em>pretty.</em></p>

<p style="text-align: justify;">Bạn có thể thấy ở đây, decorator đã thêm một hàm mới cho hàm ban đầu. Hãy hình dung nó như kiểu đóng gói một món quá. Các decorator là lớp bọc ở ngoài, bản chất của đối tượng được decorator truyền vào làm tham số (món quà bên trong) không thay đổi, nhưng hiện giờ nó có thêm một lớp bọc decorator ở ngoài.</p>

<p style="text-align: justify;">Nói chung, ở đây ta decorator một hàm và gán lại nó:</p>

<pre id="pre7">
<code>ordinary = make_pretty(ordinary)</code></pre>

<p style="text-align: justify;">Đây là một cấu trúc phổ biến, vì vậy Python có một cú pháp để đơn giản hóa việc này.</p>

<p style="text-align: justify;">Bạn có thể sử dụng ký hiệu&nbsp;<code>@</code>&nbsp;cùng với tên của hàm decorator và đặt nó lên trên định nghĩa của hàm được decorator. Ví dụ:</p>

<pre id="pre8">
<code>@make_pretty
 def ordinary():
     print(&quot;I am ordinary&quot;)</code></pre>

<p style="text-align: justify;">tương đương với:</p>

<pre id="pre9">
<code>def ordinary():
     print(&quot;I am ordinary&quot;)
 ordinary = make_pretty(ordinary)</code></pre>

<p style="text-align: justify;">Đây là một cú pháp đặc biệt để thực hiện decorator.</p>

<div style="text-align: justify;">&nbsp;</div>

<h2 style="text-align: justify;">Tham số hàm decorator</h2>

<p style="text-align: justify;">Các decorator ở trên đều khá đơn giản và hoạt động cùng với các hàm không có bất kỳ tham số nào. Bây giờ ta hãy thử truyền tham số cho hàm trả về bởi decorator như sau:</p>

<pre id="pre10">
<code>def divide(a, b):
     return a/b</code></pre>

<p style="text-align: justify;">Hàm này có hai tham số, a và b, sẽ báo lỗi nếu&nbsp;<code>b=0</code>.&nbsp;</p>

<pre id="pre11">
<code>&gt;&gt;&gt; divide(2,5)
 0.4
 &gt;&gt;&gt; divide(2,0)
 Traceback (most recent call last):
 ...
 ZeroDivisionError: division by zero</code></pre>

<p style="text-align: justify;">Khi ta gọi hàm là thực ra gọi hàm được trả về bởi decorator, nên nếu truyền tham số cho hàm này thì nó sẽ truyền cho hàm được decorate.</p>

<p style="text-align: justify;">Bây giờ chúng ta hãy tạo một decorator để kiểm tra trường hợp này có xảy ra lỗi hay không.</p>

<pre id="pre12">
<code>def smart_divide(func):
    def inner(a,b):
       print(&quot;I am going to divide&quot;,a,&quot;and&quot;,b)
       if b == 0:
          print(&quot;Whoops! cannot divide&quot;)
          return
       return func(a,b)
    return inner
 @smart_divide
 def divide(a,b):
     return a/b</code></pre>

<p style="text-align: justify;">Chương trình sẽ trả về&nbsp;<code>None</code>&nbsp;nếu có lỗi phát sinh.</p>

<pre id="pre13">
<code>&gt;&gt;&gt; divide(2,5)
 I am going to divide 2 and 5
 0.4
 &gt;&gt;&gt; divide(2,0)
 I am going to divide 2 and 0
 Whoops! cannot divide</code></pre>

<p style="text-align: justify;">Đây chính là cách sử dụng hàm decorator có tham số.</p>

<p style="text-align: justify;">Ngoài ra, bạn có thể xây dựng một decorator với số lượng tham số khác nhau tùy ý, chỉ cần sử dụng cú pháp&nbsp;<em>*args</em>&nbsp;và&nbsp;<em>**kwargs.</em></p>

<pre id="pre14">
<code>def works_for_all(func):
     def inner(*args, **kwargs):
         print(&quot;I can decorate any function&quot;)
         return func(*args, **kwargs)
     return inner</code></pre>

<p style="text-align: justify;">Khi ta gọi hàm, thực ra là chúng ta gọi hàm được trả về bởi decorator, nên nếu chúng ta truyền tham số cho hàm này thì nó sẽ truyền cho hàm được decorate.</p>

<h2 style="text-align: justify;">Chuỗi Decorator trong Python</h2>

<p style="text-align: justify;">Nhiều decorator có thể được tạo thành chuỗi decorator trong Python.</p>

<p style="text-align: justify;">Nghĩa là một hàm có thể được decorate nhiều lần với các decorator giống hoặc khác nhau, chỉ cần đặt decorator lên trước hàm bạn muốn là được.</p>

<pre id="pre15">
<code>def star(func):
     def inner(*args, **kwargs):
         print(&quot;*&quot; * 30)
         func(*args, **kwargs)
         print(&quot;*&quot; * 30)
     return inner
 def percent(func):
     def inner(*args, **kwargs):
         print(&quot;%&quot; * 30)
         func(*args, **kwargs)
         print(&quot;%&quot; * 30)
     return inner
 @star
 @percent
 def printer(msg):
     print(msg)
 printer(&quot;Hello&quot;)</code></pre>

<p style="text-align: justify;">Chương trình sẽ trả về output:</p>

<pre id="pre16">
<code>******************************
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 Hello
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 ******************************</code></pre>

<p style="text-align: justify;">Cú pháp:</p>

<pre id="pre17">
<code>@star
 @percent
 def printer(msg):
     print(msg)
 </code></pre>

<p style="text-align: justify;">tương đương với:</p>

<pre id="pre18">
<code>def printer(msg):
     print(msg)
 printer = star(percent(printer))</code></pre>

<p style="text-align: justify;">Thứ tự của decorator cũng quan trọng, nếu bạn đảo ngược:&nbsp;</p>

<pre id="pre19">
<code>@percent
 @star
 def printer(msg):
     print(msg)</code></pre>

<p style="text-align: justify;">Kết quả sẽ khác:</p>

<pre id="pre20">
<code>%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 ******************************
 Hello
 ******************************
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%</code></pre>
		</div>
				<div id="author">
						<p>
				<strong>Nguồn tin:</strong>
				Quantrimang.com
			</p>
		</div>
	</div>
	<div id="footer" class="clearfix">
		<div id="url">
			<strong>URL của bản tin này: </strong><a href="https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/decorator-trong-python-521.html" title="Decorator trong Python">https://www.nguoicodonvn2008.info/vi/news/savefile/kien-thuc-may-tinh/decorator-trong-python-521.html</a>

		</div>
		<div class="clear"></div>
		<div class="copyright">
			&copy; .&#x3A; Nguoicodonvn2008.info - Cõi lòng người cô đơn &#x3A;.
		</div>
		<div id="contact">
			<a href="mailto:admin@nguoicodonvn2008.info">admin@nguoicodonvn2008.info</a>
		</div>
	</div>
</div>
        <div id="timeoutsess" class="chromeframe">
            Bạn đã không sử dụng Site, <a onclick="timeoutsesscancel();" href="https://www.nguoicodonvn2008.info/#">Bấm vào đây để duy trì trạng thái đăng nhập</a>. Thời gian chờ: <span id="secField"> 60 </span> giây
        </div>
        <div id="openidResult" class="nv-alert" style="display:none"></div>
        <div id="openidBt" data-result="" data-redirect=""></div>
		</script>
		<div class="car-top">
  <span><img src="https://www.nguoicodonvn2008.info/themes/default/images/car.png" alt=""></span>
</div>
<script src="https://www.nguoicodonvn2008.info/assets/js/jquery/jquery.min.js"></script>
<script>var nv_base_siteurl="/",nv_lang_data="vi",nv_lang_interface="vi",nv_name_variable="nv",nv_fc_variable="op",nv_lang_variable="language",nv_module_name="news",nv_func_name="savefile",nv_is_user=0, nv_my_ofs=-4,nv_my_abbr="EDT",nv_cookie_prefix="nv4c_e856T",nv_check_pass_mstime=1738000,nv_area_admin=0,nv_safemode=0,theme_responsive=0,nv_recaptcha_ver=2,nv_recaptcha_sitekey="",nv_recaptcha_type="image",XSSsanitize=1;</script>
<script src="https://www.nguoicodonvn2008.info/assets/js/language/vi.js"></script>
<script src="https://www.nguoicodonvn2008.info/assets/js/DOMPurify/purify3.js"></script>
<script src="https://www.nguoicodonvn2008.info/assets/js/global.js"></script>
<script src="https://www.nguoicodonvn2008.info/assets/js/site.js"></script>
<script src="https://www.nguoicodonvn2008.info/themes/default/js/news.js"></script>
<script src="https://www.nguoicodonvn2008.info/themes/default/js/main.js"></script>
<script src="https://www.nguoicodonvn2008.info/themes/default/js/custom.js"></script>
<script type="application/ld+json">
        {
            "@context": "https://schema.org",
            "@type": "Organization",
            "url": "https://www.nguoicodonvn2008.info",
            "logo": "https://www.nguoicodonvn2008.info/uploads/angel.gif"
        }
        </script>
<script src="https://www.nguoicodonvn2008.info/themes/default/js/bootstrap.min.js"></script>
<script type="text/javascript">
var $scrolltop = $('.car-top');
$scrolltop.on('click', function () {
    $('html,body').animate({
        scrollTop: 0
    }, 800);
    $(this).addClass("car-run");
    setTimeout(function(){ $scrolltop.removeClass('car-run');}, 1000);
    return false;
});
$(window).on('scroll', function ()
{ 
    if($(window).scrollTop() >= 200)
    {
        $scrolltop.addClass("show");
        $scrolltop.addClass("car-down");
    }
    else
    {
       $scrolltop.removeClass("show");
       setTimeout(function(){ $scrolltop.removeClass('car-down');}, 300);
    }
});
</script>
</body>
</html>