Happy Coding ¯\_(ツ)_/¯ Built on Jekyll with a lot of _text_ and _coffee_. https://vuonghv.github.io/ Sun, 07 Feb 2021 13:53:41 +0000 Sun, 07 Feb 2021 13:53:41 +0000 Jekyll v3.9.0 Pyenv with Virtualenv: Cặp đôi hoàn hảo <h1 id="pyenv-là-gì">Pyenv là gì?</h1> <p>Nếu đã từng phải làm việc với nhiều project Python, trong đó mỗi project lại yêu cầu các phiên bản Python khác nhau, có lẽ bạn phải đối mặt với vấn đề cài đặt và chọn lựa phiên bản Python cho project của mình.</p> <p>Hơn nữa, các bản Python được cài đặt sẵn trong OS thường rất chậm trong việc cập nhật các tính năng mới vì mục đích ổn định, do đó nếu bạn muốn test thử các tính năng mới, bạn thường đi đến 2 lựa chọn sau:</p> <ol> <li>Tự build và cập nhật phiên bản Python của OS, nhưng việc này ẩn chứa nhiều rủi ro, có thể những thành phần khác sẽ chưa tương thích với phiên bản mới này.</li> <li>Sử dụng máy ảo hoặc docker, nhưng nhiều lúc chúng quá rườm rà và phức tạp. Dù sao thì gõ lệnh trực tiếp trên máy thật vẫn nhanh gọn hơn phải không?</li> </ol> <p>Được tạo ra để giải quyết các vấn đề trên, <a href="https://github.com/pyenv/pyenv">Pyenv</a> là công cụ quản lý phiên bản Python, giúp việc cài đặt các phiên bản Python khác nhau cực kỳ dễ dàng. Pyenv tích hợp với plugin <a href="https://github.com/pypa/virtualenv">Virtualenv</a> hỗ trợ tạo ra các môi trường ảo (virtual environment), các thư viện của project sẽ được cài đặt cô lập trong môi trường ảo này mà không ảnh hưởng đến hệ thống.</p> <p>Một tính năng cực kỳ hữu dụng của Pyenv, không thể bỏ qua, đó là câu lệnh <code class="language-plaintext highlighter-rouge">pyenv local</code>: <strong>tự động kích hoạt (activate)</strong> môi trường ảo khi bạn cd vào thư mục project của mình, và <strong>tự động tắt (deactivate)</strong> môi trường khi bạn rời khỏi thư mục đó.</p> <h1 id="cài-đặt">Cài đặt</h1> <p>Bạn có thể xem hướng dẫn cài đặt từ trang chủ của Pyenv trên Github hoặc sử dụng tool <a href="https://github.com/pyenv/pyenv-installer">pyenv-installer</a> như bên dưới:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl <span class="nt">-L</span> https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash </code></pre></div></div> <p>Sau đó chèn 3 dòng dưới đây vào file cấu hình shell (vd file <code class="language-plaintext highlighter-rouge">~/.bashrc</code> với Bash hoặc <code class="language-plaintext highlighter-rouge">~/.zshrc</code> cho Zsh) để tự động load <code class="language-plaintext highlighter-rouge">pyenv</code> khi mở một termial mới:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">"~/.pyenv/bin:</span><span class="nv">$PATH</span><span class="s2">"</span> <span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>pyenv init -<span class="si">)</span><span class="s2">"</span> <span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>pyenv virtualenv-init -<span class="si">)</span><span class="s2">"</span> </code></pre></div></div> <h1 id="sử-dụng">Sử dụng</h1> <p>Bên dưới mình sẽ demo cách sử dụng pyenv để thiết lập môi trường ảo sử dụng python 3.6.6 cho project demo, giả sử có đường dẫn là <code class="language-plaintext highlighter-rouge">~/projects/demo</code>:</p> <ol> <li> <p>Cài đặt phiên bản Python mong muốn sử dụng pyenv:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">$ </span>pyenv <span class="nb">install </span>3.6.6 </code></pre></div> </div> <p>Nếu cài đặt bị lỗi, có thể hệ thống của bạn thiếu các thư viện cần thiết cho việc compile, cài đặt các thư việc còn thiếu tại đây <a href="https://github.com/pyenv/pyenv/wiki/Common-build-problems">https://github.com/pyenv/pyenv/wiki/Common-build-problems</a></p> </li> <li> <p>Tạo môi trường ảo với virtualenv, môi trường này sử dụng Python 3.6.6. Ở đây mình đặt tên là <code class="language-plaintext highlighter-rouge">demo-env</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">$ </span>pyenv virtualenv 3.6.6 demo-env </code></pre></div> </div> </li> <li> <p>Kích hoạt môi trường ảo vừa tạo cho project của mình, sử dụng <code class="language-plaintext highlighter-rouge">pyenv local</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nv">$ </span><span class="nb">cd</span> ~/projects/demo <span class="nv">$ </span>pyenv <span class="nb">local </span>demo-env <span class="nv">$ </span>python <span class="nt">--version</span> <span class="c"># Test the new env</span> Python 3.6.6 <span class="c"># Bingo</span> </code></pre></div> </div> <p>Câu lệnh <code class="language-plaintext highlighter-rouge">pyenv local</code> chỉ cần chạy một lần duy nhất, môi trường sẽ được kích hoạt tự động mỗi khi bạn cd vào thư mục project của mình sau này.</p> </li> </ol> <p>Đối với mình, Pyenv + Virtualenv là cặp đôi hoàn hảo, bộ công cụ không thể thiếu trong công việc hàng ngày. Trên đây là chia sẻ về kinh nghiệm làm việc với Python của mình, mong nhận được góp ý và chia sẻ của các bạn.</p> <p>_EOF_</p> Sat, 24 Nov 2018 07:13:13 +0000 https://vuonghv.github.io/blog/pyenv-virtualenv-perfect-couple.html https://vuonghv.github.io/blog/pyenv-virtualenv-perfect-couple.html python tools blog Strong vs Weak, Static vs Dynamic typing là cái khỉ gì? <p>Trên con đường đến với đạo lập trình, chắc các bạn cũng từng nghe đến các khái niệm như <code class="language-plaintext highlighter-rouge">strong/weak</code> typing, <code class="language-plaintext highlighter-rouge">static/dynamic</code> typing. Bạn có bao giờ thắc mắc chúng có nghĩa là gì? và các ngôn ngữ thông dụng như Java, C/C++, Python, Javascript, … là strong hay weak typing? static hay dynamic typing?</p> <p>Hơn nữa, nhiều người vẫn đang nhầm tưởng rằng <em>static</em> đồng nghĩa với <em>strong</em> typing và <em>dynamic</em> đồng nghĩa với <em>weak</em> typing. Vậy bạn hãy cùng tôi dạo qua bài viết này để có một cái nhìn cụ thể hơn.</p> <h2 id="strong-vs-weak-typing">Strong vs Weak typing</h2> <p>Hiện tại thì người ta vẫn chưa thống nhất một <em>định nghĩa chuẩn</em> thế nào là một ngôn ngữ strong typing hay weak typing. Và đây cũng là một chủ đề gây ra rất nhiều tranh luận mỗi khi có ai đó nêu ra. Ở đây tôi muốn nêu ra khái niệm được nhiều người chấp nhận và theo tôi thấy thì cũng ngắn gọn và dễ hiểu nhất:</p> <blockquote> <p>Strong typing means that the type of a value doesn’t <strong>suddenly</strong> change.</p> </blockquote> <p>Theo đó, các ngôn ngữ <strong>strong typing</strong> đảm bảo rằng kiểu (types) của một object không thay đổi một cách đột ngột, không tường minh. Hay nói cách khác, ta phải chỉ rõ thao tác (thông qua lời gọi hàm, ép kiểu, …) khi muốn chuyển đổi kiểu của một object.</p> <p>Những ngôn ngữ không đáp ứng yêu cầu trên là <strong>weak typing</strong>.</p> <p><em>Nói nhiều quá, lấy một số ví dụ cho dễ hiểu nào?</em></p> <p>Xét đoạn code PHP sau:</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$a</span> <span class="o">=</span> <span class="s2">"3"</span> <span class="o">+</span> <span class="s2">"5"</span><span class="p">;</span> <span class="c1">// $a === 8</span> <span class="nv">$b</span> <span class="o">=</span> <span class="mi">101</span> <span class="mf">.</span> <span class="s2">" dogs"</span><span class="p">;</span> <span class="c1">// $b === "101 dogs"</span> </code></pre></div></div> <p>Ta thấy ở câu lệnh trên, kiểu của string <code class="language-plaintext highlighter-rouge">"3"</code> và <code class="language-plaintext highlighter-rouge">"5"</code> đã tự động chuyển thành số nguyên <code class="language-plaintext highlighter-rouge">3</code> và <code class="language-plaintext highlighter-rouge">5</code>, dẫn đến giá trị của biến <code class="language-plaintext highlighter-rouge">$a</code> là <code class="language-plaintext highlighter-rouge">8</code>. Tương tự, số nguyên <code class="language-plaintext highlighter-rouge">101</code> đã ngầm định chuyển thành string <code class="language-plaintext highlighter-rouge">"101"</code>. Do đó PHP là một ngôn ngữ weak typing.</p> <p>Tương tự, Javascript cũng là ngôn ngữ weak typing:</p> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">let</span> <span class="nx">a</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">abc</span><span class="dl">"</span> <span class="o">+</span> <span class="mi">123</span><span class="p">;</span> <span class="c1">// 123 is implicitly converted to string "123"</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">a</span><span class="p">);</span> <span class="c1">// "abc123"</span> </code></pre></div></div> <p>Trái lại, ta cùng xem đoạn code Python dưới đây:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> <span class="s">"abc"</span> <span class="o">+</span> <span class="mi">3</span> <span class="n">Traceback</span> <span class="p">(</span><span class="n">most</span> <span class="n">recent</span> <span class="n">call</span> <span class="n">last</span><span class="p">):</span> <span class="n">File</span> <span class="s">"&lt;stdin&gt;"</span><span class="p">,</span> <span class="n">line</span> <span class="mi">1</span><span class="p">,</span> <span class="ow">in</span> <span class="o">&lt;</span><span class="n">module</span><span class="o">&gt;</span> <span class="nb">TypeError</span><span class="p">:</span> <span class="n">Can</span><span class="s">'t convert '</span><span class="nb">int</span><span class="s">' object to str implicitly &gt;&gt;&gt; "abc" + str(3) '</span><span class="n">abc3</span><span class="s">' </span></code></pre></div></div> <p>Ta thấy rằng, khi cố gắng thực hiện phép toán cộng giữa một object string và một số nguyên, trình thông dịch Python sẽ thông báo lỗi <code class="language-plaintext highlighter-rouge">TypeError</code> bởi vì ta không được phép <em>ngầm định</em> chuyển đổi object kiểu int sang kiểu string. Thay vào đó, ta phải chỉ rõ <em>tưòng minh</em> thao tác chuyển đổi kiểu thông qua hàm <code class="language-plaintext highlighter-rouge">str()</code>.</p> <p>Nếu không quá khắt khe thì ta có thể coi Python là ngôn ngữ strong typing, bởi vì Python vẫn có một số ngoại lệ, ví dụ như biểu thức <code class="language-plaintext highlighter-rouge">1.0 + 2</code> sẽ cho ra giá trị là số thực <code class="language-plaintext highlighter-rouge">3.0</code> (số nguyên <code class="language-plaintext highlighter-rouge">2</code> đã tự động chuyển sang kiểu số thực).</p> <p>Với strong typing, chương trình của chúng ta sẽ rõ ràng, dễ debug và kiểm soát hơn so với weak typing. Bất cứ khi nào ta thực hiện một thao tác với các đối tượng có kiểu không tương thích nhau, chương trình sẽ xuất ra một thông báo lỗi sai kiểu (chẳng hạn <code class="language-plaintext highlighter-rouge">TypeError</code> exception trong Python). Chúng ta không cần phải nhớ một đống quy tắc tự động chuyển đổi kiểu trong các phép toán cơ bản ( ví dụ như, khi nào thì string sẽ tự động chuyển sang kiểu số, và ngược lại, …) và hơn nữa, rất khó để debug khi biến <em>âm thầm</em> đổi kiểu mà ta không biết.</p> <h2 id="static-vs-dynamic-typing">Static vs Dynamic typing</h2> <p>Trong các ngôn ngữ <strong>static typing</strong> (C/C++, Java), mỗi biến (<em>variable</em>) có một kiểu cố định liên kết với nó. Kiểu của biến được kiểm tra lúc <strong>compiled-time</strong> và trình biên dịch yêu cầu ta phải khai báo rõ kiểu của biến trước khi sử dụng.</p> <p>Ví dụ về khai báo biến trong C:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span><span class="p">;</span> <span class="c1">// the type of a is integer</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span> <span class="c1">// OK, assign 3 to a</span> <span class="n">a</span> <span class="o">=</span> <span class="s">"Hello"</span><span class="p">;</span> <span class="c1">// Error, cannot assign string value to int</span> </code></pre></div></div> <p>Nếu ta đã khai báo một biến có kiểu nguyên, ta sẽ không thể gán các giá trị có kiểu khác tới nó.</p> <p>Trái lại, với <strong>dynamic typing</strong>, mỗi biến chỉ đơn giản là một cái nhãn (label) được liên kết với một object. Mỗi object sẽ có kiểu riêng của nó (ví dụ trong Python, ta có kiểu <code class="language-plaintext highlighter-rouge">int, str, list, dict, ...</code>) nhưng bản thân biến thì không. Và kiểu của biến hay nói chính xác hơn là kiểu của object liên kết với biến được kiểm tra lúc <strong>runtime</strong>.</p> <p>Dynamic typing trong Python:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">b</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1"># variable b is bound to integer object </span><span class="nb">isinstance</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span> <span class="c1"># True </span> <span class="n">b</span> <span class="o">=</span> <span class="s">'hello world!'</span> <span class="c1"># Now b is bound to string object </span><span class="nb">isinstance</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="c1"># True </span> <span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="s">'blue'</span><span class="p">,</span> <span class="s">'black'</span><span class="p">,</span> <span class="s">'brown'</span><span class="p">]</span> <span class="c1"># Now b is a list </span></code></pre></div></div> <p>Tuy rằng có thể gán các object có kiểu khác nhau cho cùng một biến trong các ngôn ngữ dynamic typing nhưng việc đấy được xem như <em>bad practice</em> trong coding. Bởi vì việc thay đổi kiểu của biến tùy tiện sẽ làm cho code của chương trình rất khó đọc và khó debug.</p> <p><em>Nghe cũng thú vị đấy, nói nghe ưu nhược điểm của từng loại xem nào?</em></p> <p>Dưới đây là so sánh ưu nhược điểm của static với dynamic typing theo một số tiêu chí phổ biến:</p> <ul> <li> <p><strong>Ngắn gọn</strong>: Với dynamic typing, code trông sẽ ngắn gọn hơn bởi vì nó bỏ đi các khai báo kiểu cho biến, tham số cũng như giá trị trả về của hàm.</p> </li> <li> <p><strong>Tài liệu</strong>: Với tiêu chí này thì static typing lại chiếm ưu thế hơn, khi khai báo kiểu cho biến, tham số,… bản thân nó cũng đã phục vụ như bản đặc tả tài liệu. Hơn nữa static typing giúp tính năng intelligent completion trong IDE làm việc tốt hơn. Gần đây Python (version 3.5) có <a href="https://www.python.org/dev/peps/pep-0484/">type hints</a> và Microsoft đẻ ra thằng <a href="https://www.typescriptlang.org/">typescript</a> cũng có một phần vì lý do này.</p> </li> <li> <p><strong>Tính đúng đắn</strong>: Trong một ngôn ngữ static typing, những lỗi về kiểu (type errors) có thể được phát hiện tại thời điểm compile vì vậy chương trình sẽ an toàn và ít lỗi hơn so với dynamic typing, do lỗi về kiểu chỉ có thể phát hiện lúc chạy chương trình.</p> </li> <li> <p><strong>Hiệu năng</strong>: Trong ngôn ngữ dynamic typing, do phải mất chi phí để kiểm tra kiểu lúc runtime nên hiệu năng sẽ giảm đi đáng kể. Trái lại, static typing cho phép compiler thực hiện một số tối ưu lúc biên dịch chương trình do kiểu của biến đã được khai báo trước.</p> </li> </ul> <h2 id="kết-luận">Kết luận</h2> <p>Phần này chỉ đơn giản là tóm tắt lại những gì được nói ở trên.</p> <p>Strong typing đảm bảo rằng kiểu của một object không tự động thay đổi, hay nói cách khác là không thay đổi một cách ngầm định. Trong khi đó, với static typing, một biến chỉ có một kiểu duy nhất và phải được khai báo trước khi sử dụng, kiểu của biến được kiểm tra tại thời điểm biên dịch chương trình.</p> <p>Với weak typing, kiểu của một object có thể tự động thay đổi (cái này Tây họ gọi là “implicit conversions”). Trong khi đó, với các ngôn ngữ dynamic typing, ta có thể gán các object có kiểu khác nhau cho cùng một biến và kiểu của object gắn liền với biến được kiểm tra lúc chạy chương trình.</p> <p>Qua bài viết, hi vọng bạn đã có thêm một số kiến thức cũng như biết được sự khác nhau giữa các hệ thống kiểu (typed system) trong ngôn ngữ lập trình.</p> <p>Rất mong nhận được sự góp ý cũng như thảo luận từ các bạn!</p> <p>Nguồn tham khảo:</p> <ol> <li><a href="https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language">Why is Python a dynamic language and also a strongly typed language</a></li> <li><a href="http://stackoverflow.com/a/11328980/5514109">Is Python strongly typed?</a></li> <li><a href="http://stackoverflow.com/a/2690593/5514109">The difference between a strongly and a statically typed language?</a></li> </ol> <p>_EOF_</p> Sun, 23 Oct 2016 03:36:13 +0000 https://vuonghv.github.io/blog/strong-weak-static-dynamic-typing.html https://vuonghv.github.io/blog/strong-weak-static-dynamic-typing.html python programming blog