Kiến trúc lập trình Python - Phần 5

vào lúc 07:40
V. Các kỹ thuật vềmodule
1. Khái niệm và cách sử dụng module trong python
Như đã nói,Python cho phép chia chương trình thành modules để có thể sử dụng lại trong các chương trình khác. Nó cũng có sẵn một tập hợp các modules chuẩn mà ta có thể sử dụng lại trong chương trình của ta. Các thư viện này cung cấp nhiều thứ, như file I/O, các lời gọi hệ thống, sockets,…Trong phần này chúng ta sẽ tìm hiểu các kỹ thuật, đặc điểm của các module.

Nếu  thoát khỏi trình thông dịch Python và vào lại nó, những định nghĩa (các hàm và biến) đã viết sẽ bị mất. Vì thế, nếu muốn viết chương trình tồn tại được lâu, tốt nhất là sử dụng một trình soạn thảo để viết một file làm đầu vào cho trình biên dịch rồi chạy file đó. Cái này được gọi là một script (kịch bản). Hoặc khi muốn sử dụng một hàm đã xây dựng trong một vài chương trình mà không muốn copy định nghĩa của nó vào từng chương trình. Để hỗ trợ điều này, Python có một cách đặt các định nghĩa hàm trong một file và sử dụng chúng như một kịch bản hoặc trong một instance tương tác của trình thông dịch. Một file như vậy gọi là một module. Các định nghĩa từ một module có thể được nhập vào một module khác hoặc vào module chính (tập hợp các biến mà có thể truy nhập đến một script được thi hành tại mức cao nhất và trong chế độ tính toán).
Một module là một file chứa các định nghĩa và câu lệnh Python. Tên file là tên module với phần mở rộng là .py. Trong một module, tên của module (như là một xâu) là sẵn có như giá trị của biến toàn cục __name__. Ví dụ, dùng trình soạn thảo, soạn file fibo.py với nội dung như sau:
. # Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print b,
        a, b = b, a+b

def fib2(n): # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result

Bây giờ mở trình thông dịch Pyhton và nhập module này bằng lệnh dưới đây:

>>> import fibo
Thao tác này không nhập tên của các hàm đã được định nghĩa trong fibo trực tiếp vào trong bảng kí hiệu hiện thời; nó chỉ nhập tên của module fibo vào đó. Sử dụng tên module này để có thể truy nhập vào các hàm:
>>> fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
           
        Để thuận tiện, một hàm trong module định sử dụng thường được đăng kí với một tên cục bộ:

>>> fib = fibo.fib
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
         Một module có thể chứa các câu lệnh thực thi cũng như các định nghĩa hàm. Các câu lệnh đó được dùng để khởi tạo module đó. Chúng được thực hiện chỉ lần đầu tiên module đó được nhập.
         Mỗi một module có bảng kí hiệu riêng của nó, cái mà được sử dụng như một bảng kí hiệu toàn cục cho tất cả các hàm được định nghĩa trong module đó. Vì thế, các biến toàn cục trong module có thể sử dụng mà không lo lắng về sự xung đột xảy ra với các biến toàn cục của người sử dụng module đó.
         Module cũng có thể được nhập vào một module khác. Nó như là một thông lệ nhưng không yêu cầu phải đặt tất cả các câu lệnh import tại vị trí bắt đầu của một module (hoặc script). Tên module được nhập vào đó được đặt trong bảng kí hiệu toàn cục của module nhập  module đó.
         Để sử dụng modules trong Python, phải nhập nó bằng câu lệnh import. Ví dụ:
import math
        Thao tác này sẽ nhập module chuẩn math. Tất cả các hàm trong module này được gọi bằng cách sử dụng qua tên module, ví dụ:
import math
print math.sqrt(10)
        Có một biến thể của câu lệnh import mà nhập các tên từ một module trực tiếp vào bảng kí hiệu của module chứa module nhập đó. Ví dụ:
>>> from fibo import fib, fib2
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
          Cũng có một biến thể để nhập tất cả các tên mà một module định nghĩa:
>>> from fibo import *
>>> fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

        Thao tác này nhập tất cả các tên ngoại trừ những tên bắt đầu bằng dấu gạch dưới _

Đường dẫn tìm kiếm module

         Khi một module tên là spam được nhập, trình thông dịch sẽ tìm một file tên là spam.py trong thư mục hiện hành, và sau đó trong danh sách các thư mục xác định bởi biến môi trường PYTHONPATH. Khi biến PYTHONPATH chưa được thiết lập hoặc khi file đó không được tìm thấy, việc tìm kiếm được tiếp tục trong một đường dẫn mặc định phụ thuộc khi cài đặt.

         Thực tế, các module được tìm kiếm trong danh sách các thư mục được đưa ra bởi biến sys.path cái mà được khởi tạo từ thư mục chứa script vào ( hoặc thư mục hiện hành), PYTHONPATH và thư mục đường dẫn mặc định phụ thuộc vào cài đặt. Điều này cho phép chương trình Python biết cái mà chúng đang làm để sửa đổi hoặc thay thế đường dẫn tìm kiếm module.
2. Các module chuẩn
         Python cung cấp một thư viện các module chuẩn. Một số module quan trọng được cài sẵn vào trình thông dịch. Có một module cụ thể đáng để chú ý là: sys, module này được cài sẵn vào mọi trình thông dịch Python. Các biến sys.ps1 và sys.ps2 định nghĩa các xâu được sử dụng như dấu nhắc sơ cấp và thứ cấp:
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print 'Yuck!'
Yuck!
C>
        Hai biến trên chỉ được định nghĩa nếu trình thông dịch ở chế độ tương tác.
        Biến sys.path là một danh sách các xâu mà xác định đường dẫn tìm kiếm module của trình thông dịch. Nó được khởi tạo một đường dẫn mặc định từ biến môi trường PYTHONPATH, hoặc từ một giá trị mặc định được cài sẵn nếu PYTHONPATH không được thiết lập. Có thể sửa đổi nó sử dụng thao tác danh sách chuẩn:

>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
           
        Sau đây là danh sách đầy đủ các module chuẩn đã xây dựng trong Python. Một số module có kèm theo tên các nền tảng mà module đó được sử dụng:


3. Thư viện các module chuẩn:
Phần này sẽ trình bày về một số module chuẩn đã được xây dựng sẵn trong Python.
3.1. Giao diện hệ điều hành
        Module os cung cấp rất nhiều hàm tương tác với hệ điều hành:

>>> import os
>>> os.system('time 0:02')
0
>>> os.getcwd()
# Return the current working directory
'C:\\Python24'
>>> os.chdir('/server/accesslogs')

        Hai hàm dir( ) và help( ) được dùng như những trợ giúp khi làm việc vói các modules lớn như os:

>>> import os
>>> dir(os)
<returns a list of all module functions>
>>> help(os)
<returns an extensive manual page created from the module's docstrings>

        Đối với nhiệm vụ quản lý thư mục và file hằng ngày, module shutil cung cấp sự tương tác  mức độ cao hơn, sử dụng dễ dàng hơn:

>>> import shutil
>>> shutil.copyfile('data.db', 'archive.db')
>>> shutil.move('/build/executables', 'installdir')

3.2  Tệp với các kí tự đại diện
        Module glob cung cấp một hàm để tạo danh sách từ việc tìm kiếm một thư mục dùng các kí tự đại diện. Ví dụ:

>>> import glob
>>> glob.glob('*.py')
['primes.py', 'random.py', 'quote.py']

3.3 Đối số dòng lệnh
        Các script tiện ích phổ biến thường cần thiết lúc xử lý đối số dòng lệnh. Các đối số này được lưu trữ trong thuộc tính argv của module sys như một danh sách.Ví dụ sau đưa ra kết quả khi chạy  “python demo.py one two three" tại dòng lệnh:
>>> import sys
>>> print sys.argv
['demo.py', 'one', 'two', 'three']

3.4. Sự đổi hướng xuất lỗi và phần kết thúc chương trình
        Module sys cũng có các thuộc tính cho stdin, stdout và stderr . Đoạn mã sau để tạo ra các cảnh báo và thông điệp lỗi làm cho chũng xuất hiện ngay cảkhi stdout được định hướng lại

>>> sys.stderr.write('Warning, log file not found starting a new one\n')
Warning, log file not found starting a new one
        Hầu hết cách định hướng để kết thúc một script là xử dụng "sys.exit()".

3.5. Kết hợp các kiểu xâu
        module re cung cấp các công cụ biểu thức thông dụng cho việc xử lý xâu nâng cao .Đối với các thao tác và biểu diễn phức tạp ,các biểu thức chính qui đưa ra các giải pháp ngắn gọn và tối ưu. Ví dụ:

>>> import re
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'

3.6. Thư viện các hàm toán học
        Danh sách các module số và toán học bao gồm:

Các hàm toán học (sin() v.v...).

Các hàm toán học cho số phức.

Khai báo của các dạng số học thập phân tổng quát

Sinh ra các số "giả" ngẫu nhiên với các hàm phân bố xác suất thông thường.

Các hàm sinh ra các “iterators” sử dụng trong các vòng lặp hiệu quả

Các hàm và thao tác có thứ tựưu tiên cao hơn trên các đối tượng gọi được

Tất cả các toán tử chuẩn của Python được cài đặt sẵn
       
        Module math cung cấp các truy cập tới các hàm thư viện cơ bản của C đối với các phép toán trên số thực

>>> import math
>>> math.cos(math.pi / 4.0)
0.70710678118654757
>>> math.log(1024, 2)
10.0
        Module random cung cấp một cách thức để tạo ra sự lựa chọn ngẫu nhiên

>>> import random
>>> random.choice(['apple', 'pear', 'banana'])
'apple'
>>> random.sample(xrange(100), 10)   # sampling without replacement
[30, 83, 16, 4, 8, 81, 41, 50, 18, 33]
>>> random.random()    # random float
0.17970987693706186
>>> random.randrange(6)    # random integer chosen from range(6)
4
        Sau đây, ta sẽ tìm hiểu về các hàm được xây dựng trong 2 module math và cmath.

a. Các hàm toán học trong module math: 
          Modul này luôn sẵn dùng. Nó cung cấp  phương thức truy nhập các hàm toán học được định nghĩa theo chuẩn C.
          Module math cung cấp các hàm dưới đây. Tất cả đều trả về số thực ngoại trừ một số trường hợp đặc biệt.
ceil(
x)
Hàm trả về giá trị cận trên của số thực x, tương ứng với giá trị nguyên nhỏ nhất lớn hơn x.
fabs(
x)
Giá trị tuyệt đối của x.
floor(
x)
Hàm trả về giá trị cận dưới của số thực x, tương ứng với giá trị nguyên lớn nhất nhỏ hơn x.
.
fmod(
x, y)
Trả về fmod(x,y), được định nghĩa theo chuẩn thư viện C. Chú ý rằng trong Python phép toán x % y có thể không trả về cùng một kết quả tương tự. Thực tế trong chuẩn thư viện C thì fmod(x,y) trả về chính xác(phép toán, độ chính xác vô hạn) bằng x-n*y với 1 vài số nguyên n có cùng kết quả với dấu của x và độ lớn trị tuyệt đối của y. Trong khi đó, đối với Python thì phép toán x % y trả về kết quả là bao gồm cả dấu của y, và nó ko thểước tính chính xác cho các đối số thực.Ví dụ, fmod(-1e-100,1e100) là -1e-100, nhưng kết quả của -1e-100 % 1e100 là -1e-100,điều này không thể đưa ra kết quả chính xác đối với số thực,  và làm tròn 1e100. Chính vì nguyên nhân này, hàm fmod() thường được ưu tiên khi làm việc với số thực, với x % y trong Python thì được ưu tiên với số nguyên.
frexp(
x)
Trả về phần định trị và số mũ của x dưới dạng (m,e). m có giá trị thực còn e là số nguyên với x == m*2**e. Nếu x = 0, kết quả là (0.0,0), còn  0.5 <= abs(m) < 1.
ldexp(
x, i)
Trả về x * (2 ** i). Là hàm ngược của hàm frexp().
modf(
x)
Trả về phần phân số và phần nguyên của x. Cả hai đều mang dấu của x và đều có giá trị thực.
Chú ý rằng frexp() và modf() có kiều gọi/ trả về khác nhau tương đương như trong C: Chúng lấy đối số đơn và trả về cặp giá trị, đúng hơn là sựtrả về giá trị thứ 2 thông qua “tham số ra”( không có những điều như vậy trong Python).
Đối với các hàm ceil(), floor() và modf(), chú ý là không phải tất cả các số thực có giá trị lớn đều chính xác là số nguyên. Số thực trong Python có độ chính xác không vượt quá 32 bít( giống với kiểu Double trong C), trong trường hợp giá trị thực x có abs(x) >=2**52 thì tất nhiên sẽ không có các bít phân số.
Các hàm mũ và logarit:
exp(
x)
        Trả về e**x
log(
x[, base])
Trả về logarit của x với cơ số đưa ra là base. Nếu không đưa cơ cố base, thì tự động trả về logarit tự nhiên của x( logarit với cơ số e).
log10(
x)
Trả về logarit cơ số 10 của x.
pow(
x, y)
Trả về x ** y
sqrt(
x)
Trả về căn bậc 2 của x.
Các hàm lượng giác:
acos(
x)
Trả về arc coosin của x theo radian.
asin(
x)
Trả về arc sin của x theo radian
atan(
x)
Trả về arc tang của x theo radian 
atan2(
y, x)
Trả về atan(y/x) theo radian. Kết quả nằm trong khoảng từ -pi đến pi. Vector trong mặt phẳng từ điểm gốc tọa độ tới điểm có tọa độ (x,y) tạo một góc với trục tọa độ X . Điểm của atan2() mà dấu của cả hai đầu vào được biết đến nó, vì vậy nó có thể tính toán chính xác độ của góc. Ví dụ, atan(1) và atan2(1,1) đều bằng pi/4 nhưng atan2(-1,-1) lại bằng –pi/4.
cos(
x)
Trả về giá trị cosin của x
hypot(
x, y)
Trả về dạng Oclit của sqrt(x*x+y*y).Đây là độ dài véc tơ từ gốc tọa độ tới điểm có tọa độ (x,y).
sin(
x)
Trả về sin của x theo radian
tan(
x)
Trả về tang của x theo radian.
Hàm chuyển đổi góc:
degrees(
x)
Chuyển góc x từ radian sang độ.
radians(
x)
Chuyển góc x từ độ sang radian.
Các hàm hypebon:
cosh(
x)
Trả vè hyperbolic cosin của x.
sinh(
x)
Trả về hyperbolic sin của x.
tanh(
x)
Trả về hyperbolic tang của x.
Các hằng số toán học được định nghĩa sẵn:
pi
Sốpi =  3.14159265358979….
e
Sốe.
b. Các hàm toán học cho số phức trong module cmath:

      Module này cung cấp cách truy nhập vào các hàm toán học cho số phức. Các hàm này gồm có:
acos(
x)
Trả về arccos của x. Có 2 miền được chọn: 1 miền kéo dài về phía phải từ 1 liên tục tới ∞. Miền còn lại kéo dài về phía trái từ -1 liên tục tới -∞.
acosh(
x)
Trả về hypedolic arccos của x. Chỉ có một miền được lấy ra, kéo dài về phía trái từ 1 liên tục cho tới -∞.
asin(
x)
Trả về arcsin của x.Có dải giá trị cũng giống như arccos().
asinh(
x)

Trả về hyperbolic arcsin của x. Có 2 miền giá trị được lấy ra, kéo dài liên tục về bên trái từ ±1j tới ±-∞j. Những miền này cần tính toán đến các lỗi để chính xác hơn. Miền chính xác được lấy ra sẽ mở rộng theo trục ảo, một liên tục từ 1j tới ∞j từ phía phải và một liên tục từ -1j tới -∞j từ phía trái.
atan(
x)
Trả về arc tang của x. Có 2 miền được lấy ra: Một kéo dài liên tục từ 1j theo trục sốảo tới ∞j từ phía trái. Miền khác kéo dài liên tục từ -1j dọc theo trục sốảo tới ∞j từ phía trái.( Điều này sẽ chắc chắn thay đổi vì với miền cao hơn sẽ liên tục từ nhiều phía khác).
atanh(
x)
Trả về hyperbolic arc tang của x. Có 2 miền giá trị được lấy ra: Một kéo dài liên tục từ 1 dọc theo trục số thực tới ∞. Miền còn lại kéo dài liên tục từ-1 dọc theo trục số thực tới -∞.( Điều này chắc chắn sẽ bị thay đổi vì miền phải lấy ra trở nên liên tục từ phía khác)

cos(
x)
Trả về cosin của x.
cosh(
x)
Trả về hyperbolic cosin của x.
exp(
x)
Trả về giá trị mũ e**x.
log(
x[, base])
Trả về logarit của x với cơ số là base. Nếu base ko được đưa ra, trả về giá trị logarit tự nhiên của x. Có một miền được lấy ra, từ 0 dọc theo miền âm trục số thực tới -∞. Được thay đổi trong phiên bản 2.4 : đối số base được thêm vào.
log10(
x)
Trả về logarit cơ số 10 của x. Có miền tương tự như hàm log()
sin(
x)
Trả về sin của x.
sinh(
x)
Trả về hyperbolic sin của x.
sqrt(
x)
Trả về căn bậc 2 của x. Miền được lấy ra tương tự như hàm log().
tan(
x)
Trả về tang của x.
tanh(
x)
Trả về hyperbolic tang của x.
Các hằng số đươc định nghĩa trong module:
pi
Hằng số pi, tương tự như số thực
e
Hằng số e, tương tự như số thực
          Chú ý rằng việc lựa chọn các hàm trong module cmath cũng gần tương tự như trong module math nhưng không hoàn toàn giống. Lý do khiến người ta xây dựng lên cả 2 module phân biệt này là vì có người sử dụng không thích dùng trong số phức, và có lẽ không cần quan tâm chúng là gì. Để xử lý với số phức họ có thể dùng hàm math.sqrt(-1), và giá trị trả về của các hàm trong cmath thì luôn là số phức, mặc dù giá trị đó có thể rõ ràng là số thực ( trong trường hợp số phức có  phần ảo là 0).
       
3.7. Truy cập internet
        Có một sốmodule để truy cập internet và xử lý các giao thức internet. Hai module đơn giản nhất là urllib2 cho việc nhận dữ liệu từ url  smtplib cho gửi mail:

>>> import urllib2
>>> for line in urllib2.urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl'):
...     if 'EST' in line or 'EDT' in line:  # look for Eastern Time
...         print line
   
<BR>Nov. 25, 09:43:32 PM EST

>>> import smtplib
>>> server = smtplib.SMTP('localhost')
>>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org',
"""To: jcaesar@example.org
From: soothsayer@example.org

Beware the Ides of March.
""")
>>> server.quit()

3.8 Xử lý ngày và thời gian với module datetime
       Module datetime cung cấp các lớp để thao với ngày và thời gian cho cả yêu cầu đơn giản và phức tạp. Module này cũng hỗ trợ các đối tượng nhận định yếu tố thời gian.
# dates are easily constructed and formatted
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2003, 12, 2)
>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.")
'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.'

# dates support calendar arithmetic
>>> birthday = date(1964, 7, 31)
>>> age = now - birthday
>>> age.days
14368

3.9. Nén dữ liệu
        Các định dạng nén và lưu trữ dữ liệu phổ biến được hỗ trợ trực tiếp bởi rất nhiều thủ tục, bao gồm:zlib,gzip,bz2,zipfile  tarfile. Ví dụ:

>>> import zlib
>>> s = 'witch which has which witches wrist watch'
>>> len(s)
41
>>> t = zlib.compress(s)
>>> len(t)
37
>>> zlib.decompress(t)
'witch which has which witches wrist watch'
>>> zlib.crc32(s)
226805979

3.10. Đánh giá khả năng thực hiện
       Một số ngưòi sử dụng Python quan tâm sâu sắc trong việc tìm hiểu sự thực thi tương đối của các cách tiếp cận khác nhau tới cùng một vấn đề
Chẳng hạn có thể thử chức năng packing và unpacking một tuple thay vì phương pháp truyền thống là đối chỗ đối sô. Module timeit cung cấp một ưu điểm thực hiện với mức độ vừa phải

>>> from timeit import Timer
>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit()
0.57535828626024577
>>> Timer('a,b = b,a', 'a=1; b=2').timeit()
0.54962537085770791

3.11. Kiểm tra chất lượng
        Một phương pháp để phát triển phần mềm chất lượng cao là viết chương trình kiểm tra cho mỗi hàm lúc nó được phát triển và chạy kiểm tra thường xuyên trong suốt quá trình phát triển
Module doctest cung cấp một công cụ cho việc kiểm tra một module và kiểm tra hợp lệ được nhúng trong một docstring của chương trình.Việc tạo kiểm tra cũng đơn giản như cắt và dán một lời gọi thông thường cùng với kết quả của nó vào docstring đó.

Def average(values):
    """Computes the arithmetic mean of a list of numbers.

    >>> print average([20, 30, 70])
    40.0
    """
    return sum(values, 0.0) / len(values)

import doctest
doctest.testmod()   # automatically validate the embedded tests

      Module unittest không cung cấp hiệu qua như module doctest nhưng nó cho phép một tập hỗn hợp của các kiểm tra được duy trì trong một file riêng biệt

import unittest
class TestStatisticalFunctions(unittest.TestCase):

    def test_average(self):
        self.assertEqual(average([20, 30, 70]), 40.0)
        self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
        self.assertRaises(ZeroDivisionError, average, [])
        self.assertRaises(TypeError, average, 20, 30, 70)

unittest.main() # Calling from the command line invokes all tests

3.12 Định dạng đầu ra
        Module repr cung cấp một phiên bản mới của hàm rept( ) tuỳ biến đối với việc hiển thị ngắn gọn của các tập lớn hoặc được lồng nhau  mức sâu.

>>> import repr   
>>>repr.repr(set('supercalifragilisticexpialidocious'))
    "set(['a', 'c', 'd', 'e', 'f', 'g', ...])"
        Module pprint đưa ra điều khiển phức tạp hơn khi in các đối tượng đã xây dựng sẵn và do người dùng định nghĩa theo một phương thức mà trình biên dịch có thể hiểu được.
        Khi kết quả dài hơn một dòng, ”pretty printer “  xuống dòng và thụt vào đầu dòng để thể hiện cấu trúc dữ liệu rõ ràng hơn
Ví dụ 2:
>>> import pprint
    >>> t = [[[['black', 'cyan'], 'black', ['green', 'red']], [['magenta',
    ...     'yellow'], 'blue']]]
    ...
    >>> pprint.pprint(t, width=30)
    [[[['black', 'cyan'],
       'black',
       ['green', 'red']],
      [['magenta', 'yellow'],
       'blue']]]

        Module textwrap định dạng đoạn văn bản để lấp đầy chiều rộng màn hình đươc cho trước:

>>> import textwrap
>>> doc = """The wrap() method is just like fill() except that it returns
    ... a list of strings instead of one big string with newlines to separate
    ... the wrapped lines."""
    ...
>>> print textwrap.fill(doc, width=40)
    The wrap() method is just like fill()
    except that it returns a list of strings
    instead of one big string with newlines
    to separate the wrapped lines.

Module locale truy cập một  cơ sở dữ liệu của các định dạng dữ liệu xác định . Nhóm các thuộc tính của các hàm trong module locale cung cấp một phương thức trực tiếp định dạng các số với việc tách thành các nhóm

>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'English_United States.1252')
 'English_United States.1252'
>>> conv = locale.localeconv()          # get a mapping of conventions
>>> x = 1234567.8
>>> locale.format("%d", x, grouping=True)
'1,234,567'
>>> locale.format("%s%.*f", (conv['currency_symbol'],
 ...          conv['frac_digits'], x), grouping=True)
'$1,234,567.80'

3.13. Kĩ thuật templating (tạm thời)
       Module string cung cấp một lớp Template linh hoạt với cấu trúc được đơn giản hoá phù hợp cho việc soạn thảo. Điều này cho phép người sử dụng tuỳ biến các ứng dụng của họ mà không cần phải thay đổi ứng dụng.
       Định dạng này sử dụng các placeholder( biến giữ chỗ) đuợc tạo thành bởi ký hiệu $ sử dụng các định danh hợp lệ của Python (chỉ gồm các ký tự chữ, số và ký tự gạch dưới). Bao quanh placeholder với dấu ngoặc {}cho phép nó đi kèm với các ký tự chữ số mà không có dấu cách xen vào giữa. Ví dụ:

>>> from string import Template
>>> t = Template('${village}folk send $$10 to $cause.')
>>> t.substitute(village='Nottingham', cause='the ditch fund')
'Nottinghamfolk send $10 to the ditch fund.'

       Phương thức substitute tạo ra một lỗi KeyError khi một placeholder không được cung cấp trong một từ điển hay một đối số từ khoá. Trong một ứng dụng dạng mail-mail, người sử dụng cung cấp dữ liệu có thể không đầy đủ và phương thức safe_substitute có thể thích hợp hơn—Nó sẽ để nguyên placeholder nếu dữ liệu bi lỗi

>>> t = Template('Return the $item to $owner.')
>>> d = dict(item='unladen swallow')
>>> t.substitute(d)
Traceback (most recent call last):
  . . .
KeyError: 'owner'
>>> t.safe_substitute(d)
'Return the unladen swallow to $owner.'

       Các Lớp con Template có thể xác định một phân định tuỳ chọn. Chẳng hạn ,một tiện ích đổi tên cho một trình duyệt ảnh có thể chọn để dùng kí hiệu %  làm placeholder như ngày hiện tại, số chuỗi ảnh hay kiểu định dạng file ảnh.

>>> import time, os.path
>>> photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg']
>>> class BatchRename(Template):
...     delimiter = '%'
>>> fmt = raw_input('Enter rename style (%d-date %n-seqnum %f-format):  ')
Enter rename style (%d-date %n-seqnum %f-format):  Ashley_%n%f

>>> t = BatchRename(fmt)
>>> date = time.strftime('%d%b%y')
>>> for i, filename in enumerate(photofiles):
...     base, ext = os.path.splitext(filename)
...     newname = t.substitute(d=date, n=i, f=ext)
...     print '%s --> %s' % (filename, newname)

img_1074.jpg --> Ashley_0.jpg
img_1076.jpg --> Ashley_1.jpg
img_1077.jpg --> Ashley_2.jpg

3.14. Làm việc với các lớp bản ghi dữ liệu nhị phân 
       Module struct cung cấp các hàm pack() và unpack() để làm việc với các định dạng bản ghi nhị phân chiều dài thay đổi. Chương trình sau chỉ ra làm thế nào lặp các thông tin header trong một file Zip ( với các mã  đóng gói “H” và “L” tương ứng số không dấu 2 và 4 bytes)

import struct
    data = open('myfile.zip', 'rb').read()
    start = 0
    for i in range(3):
# show the first 3 file headers
        start += 14
        fields = struct.unpack('LLLHH', data[start:start+16])
        crc32, comp_size, uncomp_size, filenamesize, extra_size = fields

        start += 16
        filename = data[start:start+filenamesize]
        start += filenamesize
        extra = data[start:start+extra_size]
        print filename, hex(crc32), comp_size, uncomp_size

        start += extra_size + comp_size     # skip to the next header

3.15. Kỹ thuật đa tuyến (Multi-threading)
        Đa tuyến (Threading) là một kĩ thuật cho các nhiệm vụ tách riêng mà không phụ thuộc lấn nhau. Các tuyến có thể được sử dụng để nâng cao tính đáp ứng của các ứng dụng mà chấp nhận người sử dụng nhập số liệu trong khi các nhiệm vụ khác vẫn đang chạy.
        Đoạn mã sau chỉ ra cách mà module threading có thể thực hiện các nhiệm vụ trong khi chương trình chính vẫn tiêp tục chạy

import threading, zipfile

    class AsyncZip(threading.Thread):
        def __init__(self, infile, outfile):
            threading.Thread.__init__(self)       
            self.infile = infile
            self.outfile = outfile
        def run(self):
            f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
            f.write(self.infile)
            f.close()
            print 'Finished background zip of: ', self.infile

    background = AsyncZip('mydata.txt', 'myarchive.zip')
    background.start()
    print 'The main program continues to run in foreground.'
   
    background.join()    # Wait for the background task to finish
    print 'Main program waited until background was done.'

        Vấn đề khó khăn chủ yếu của các ứng dụng đa tuyến là các tuyến này cùng chia sẻ dữ liệu và các tài nguyên khác.
        Module threading cũng cung cấp một sô công cụ đồng bộ hoá bao gồm locks, events, conditional variables và semaphore.

        Mặc dù các công cụ này là rất mạnh, nhưng có những khó khăn trong khi thiết kế để tránh các lỗi. Một phương pháp hữu hiệu là tập trung tất cả sự truy cập tới một tài nguyên trong một thread đơn, sau đó sử dụng thủ tục Queue để sử dụng thread này với các yêu cầu từ các thread khác. Ứng dụng sử dụng đối tượng Queue cho việc liên lạc các thread bên trong chương trình và sự kết hợp là dễ dàng hơn để thiết kế, dễ đọc hơn và đáng tin cậy hơn.

3.16. Thao tác Logging
        Module logging cung cấp thao tác thoát khỏi hệ thống  với đủ chức năng và linh hoạt.
        Đơn giản, một thông điệp log được gửi tới file hoặc sys.stderr

import logging
    logging.debug('Debugging information')
    logging.info('Informational message')
    logging.warning('Warning:config file %s not found', 'server.conf')
    logging.error('Error occurred')
    logging.critical('Critical error -- shutting down')

Đoạn code này đưa ra dòng thông báo sau:
 WARNING:root:Warning:config file server.conf not found
    ERROR:root:Error occurred
    CRITICAL:root:Critical error -- shutting down

         Theo mặc định, thông điệp thông tin và sữa lỗi có thể bị cấm và đầu ra chỉ được gửi tới các lỗi chuẩn. Các lựa chọn đầu ra bao gồm các thông điệp định tuyến thông qua email, datagram, socket hay HTTP server. Một bộ lọc có thể chọn định tuyến khác nhau dựa trên quyền ưu tiên của thông điệp: DEBUG, WARNING, ERROR VÀ CRITICAL
         Thao tác thoát khỏi hệ thống có thể được cấu hinh trực tiếp từ Python hoặc được nạp từ file cấu hình có thể chỉnh sửa đối vói logging tuỳ ý mà không cần thay đổi ứng dụng

3.17. Các tham chiếu lỏng lẻo:
        Pyhton tự động quản lý bộ nhớ (đếm số lần tham chiếu của hầu hết các đối tượng và tập hợp không hợp lệ để loại trừ chúng theo chu kì). Bộ nhớ sẽ được giải phóng ngay sau khi tham chiếu cuối cùng tới nó được loại bỏ.
        Phương pháp này làm việc tốt đối với hầu hết ứng dụng nhưng đôi khi, các đối tượng cần được theo dõi trong suốt quá trình chúng được sử dụng, nhưng việc theo dõi đó lại tạo ra một tham chiếu lâu dài. Module
weakref cung cấp các công cụ cho theo dõi đối tượng mà không cần tạo một tham chiếu. Khi đối tượng không còn cần nữa thì nó sẽ tự động bị xoá đi từ một bảng. Xét một ví dụ:

>>> import weakref, gc
    >>> class A:
    ...     def __init__(self, value):
    ...             self.value = value
    ...     def __repr__(self):
    ...             return str(self.value)
    ...
    >>> a = A(10)  # create a reference
    >>> d = weakref.WeakValueDictionary()
    >>> d['primary'] = a
# does not create a reference
    >>> d['primary']              
# fetch the object if it is still alive
    10
    >>> del a                      
# remove the one reference
    >>> gc.collect()               
# run garbage collection right away
    0
    >>> d['primary']               
# entry was automatically removed
    Traceback (most recent call last):
      File "<pyshell#108>", line 1, in -toplevel-
        d['primary']              
 # entry was automatically removed
      File "C:/PY24/lib/weakref.py", line 46, in __getitem__
        o = self.data[key]()
    KeyError: 'primary'

3.18. Các công cụ làm việc vói danh sách
      Module array cung cấp đối tượng array() giống như một danh sách lưu trữ chỉ dữ liệu cùng loại và lưu trữ nó liên tiếp nhau. Ví dụ sau đây chỉ ra một mảng các số được lưu trữ như số nhị phân không dấu 2 byte (mã kiểu “H”) hơn là 16 bytes thông dụng cho một mục đối với danh sách thông thường của đối tượng int của Python.

>>> from array import array
>>> a = array('H', [4000, 10, 700, 22222])
>>> sum(a)
  26932
>>> a[1:3]
  array('H', [10, 700])

       Module collections cung cấp đối tượng deque() cũng giống như danh sách nhưng tốc độ thêm vào và lấy ra từ phía trái nhanh hơn nhưng tìm kiếm bên trong chậm hơn. Đối tượng này phù hợp tốt cho sự thục hiện queue và tìm kiếm cây theo chiều rộng

>>> from collections import deque
>>> d = deque(["task1", "task2", "task3"])
>>> d.append("task4")
>>> print "Handling", d.popleft()
Handling task1

    unsearched = deque([starting_node])
    def breadth_first_search(unsearched):
        node = unsearched.popleft()
        for m in gen_moves(node):
            if is_goal(m):
                return m
            unsearched.append(m)

Ngoài ra, để lựa chọn các thao tác trên danh sách, thư viện cũng đưa ra các công cụ khác như module bisect với các hàm cho các thao tác trên danh sách được lưu trữ

>>> import bisect
>>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]
>>> bisect.insort(scores, (300, 'ruby'))
>>> scores
[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]

       Module heap cung cấp các hàm cho việc thao tác các heap dựa trên danh sách thông thường. Phần tử có giá trị thập nhất luôn ở vi trí 0 . Đây là một ứng dụng hữu ích khi phải truy cập thường xuyên tới phần tử nhỏ nhất nhưng không muốn sắp xếp toàn bộ danh sách

    >>> from heapq import heapify, heappop, heappush
    >>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
    >>> heapify(data)                     
# rearrange the list into heap order
    >>> heappush(data, -5)# add a new entry
    >>> [heappop(data) for i in range(3)]
 # fetch the three smallest entries
    [-5, 0, 1]

3.19. Số học trên dấu phẩy động hệ mười
        Module decimal đưa ra kiểu dữ liệu Decimal các phép toán số học với dấu phẩy động. So với các thao tác trên kiểu float đã có sẵn của dấu phẩy động nhị phân, lớp mới này đặc biệt có ích đối với các ứng dụng tài chính và những người sử dụng khác cần việc biểu diển chính xác số thực, kiểm soát độ chính xác, điều chỉnh việc làm tròn đúng qui tắc hay các yêu cầu điêu chỉnh, hay các ứng dụng mà người sử dụng chấp nhận kết quả được tính toán bằng tay.
        Chẳng hạn tính 5% thuế trên 70 cent tiền điện thoại đưa lại kết quả khác nhau trong kiểu số thực và số phẩy động nhị phân. Sự khác nhau này trở nên có ý nghĩa nếu kết quả được làm tròn tới cent gấn nhất

>>> from decimal import *      
>>> Decimal('0.70') * Decimal('1.05')
Decimal("0.7350")
>>> .70 * 1.05
0.73499999999999999

        Việc biểu diễn chính xác cho phép lớp Decimal thực hiện công việc tính toán và kiểm tra đẳng thức điều mà không phù hợp đối với số dấu phẩy động nhị phân

>>> Decimal('1.00') % Decimal('.10')
Decimal("0.00")
>>> 1.00 % 0.10
0.09999999999999995
      
>>> sum([Decimal('0.1')]*10) == Decimal('1.0')
True
>>> sum([0.1]*10) == 1.0
False
      Module decimal cung cấp số và độ chính xác theo yêu cầu

>>> getcontext().prec = 36
>>> Decimal(1) / Decimal(7)
Decimal("0.142857142857142857142857142857142857")

4. Hàm dir( )
       Hàm cài sẵn dir( ) được sử dụng để tìm ra các tên mà một module định nghĩa. Nó trả về một danh sách đã sắp xếp các xâu. Ví dụ:

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__',
 '__stdin__', '__stdout__', '_getframe', 'api_version', 'argv',
 'builtin_module_names', 'byteorder', 'callstats', 'copyright',
 'displayhook', 'exc_clear', 'exc_info', 'exc_type', 'excepthook',
 'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags',
 'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache',
 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags',
 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout',
 'version', 'version_info', 'warnoptions']

 Nếu không có các đối số, dir( ) liệt kê các tên đã định nghĩa hiện thời:
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__doc__', '__file__', '__name__', 'a', 'fib', 'fibo', 'sys']
     
 Chú ý rằng nó liệt kê tất cả các loại tên: biến, module, hàm v.v…
dir( ) không liệt kê các tên của các hàm và biến được cài sẵn. Nếu muốn một danh sách của chúng, chúng phải được định nghĩa trong một module chuẩn __builtin__:

>>> import __builtin__
>>> dir(__builtin__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning',
 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
 'FloatingPointError', 'FutureWarning', 'IOError', 'ImportError',
 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt',
 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented',
 'NotImplementedError', 'OSError', 'OverflowError',
 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError',
 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError',
 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True',
 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError',
 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError',
 'UserWarning', 'ValueError', 'Warning', 'WindowsError',
 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__',
 '__name__', 'abs', 'apply', 'basestring', 'bool', 'buffer',
 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile',
 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod',
 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float',
 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex',
 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter',
 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min',
 'object', 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range',
 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set',
 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super',
 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip']
 echo.echofilter(input, output, delay=0.7, atten=4)


Hãy like nếu bài viết có ích →
Kết bạn với gisgpsrs trên Facebook để nhận bài viết mới nóng hổi

Không có nhận xét nào:

Đăng nhận xét