Bước tới nội dung

Học Python/Chương IV

Tủ sách mở Wikibooks

Chương này sẽ nói về sức mạnh của Python. Như bạn đã biết, mọi thứ trong Python là một đối tượng, code được tra cứa trong các modules và phương thức trong bộ nhớ như một đối tượng, lấy thông tin về chúng, và thao tác trên chúng.

Diving In

[sửa]

Ví dụ: apihelper.py ( (http://diveintopython.org/download/diveintopython−examples−5.4.zip )


 def info(object , spacing  = 10 , collapse = 1 ):
    """ Print methods and doc string .
  
    Takes module , class , list , dictionary , or string ."""
    methodList = [method for method in dir(object) if callable(getattr(object, method))]
    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
    print "\n".join(["%s %s" %
                     (method.ljust(spacing),
                     processFunc(str(getattr(object, method).__doc__)))
                      for method in methodList])


    if __name__ == "__main__":
       print info.__doc__


  • Module này có 1 hàm , info . Trong khai báo hàm , có ba tham số : object , spacing , and collapse . Có 2 tham số được chọn lựa .
  • Hàm info có nhiều dòng doc mô tả ngắn gọn mục đích của hàm . Chú ý rằng không có giá trị trả về được đề cập .
  • Code trong hàm thì được thụt vào .
  • if __name__ lừa gạt , cho phép chương trình làm một cái gì đó hữa dụng hơn khi chạy bởi chính nó mà không quan tâm đến chương trình sử dụng module của chương trình khác . Trong trường hợp này , chương trình đơn giản chỉ in ra chuổi doc của hàm info .
  • Hàm info được thiết kế để được sử dụng bởi bạn , người lập trình , trong khi làm việc với Python IDE. Chương trình lấy bất kì đối tượng có hàm hay phương thức và in ra ngoài .


Ví dụ :

 >>> from apihelper import info
 >>> li = []
 >>> info(li)
 append L.append(object) −− append object to end
 count L.count(value) −> integer −− return number of occurrences of value
 extend L.extend(list) −− extend list by appending list elements
 index L.index(value) −> integer −− return index of first occurrence of value
 insert L.insert(index, object) −− insert object before index
 pop L.pop([index]) −> item −− remove and return item at index (default last)
 remove L.remove(value) −− remove first occurrence of value
 reverse L.reverse() −− reverse *IN PLACE*
 sort L.sort([cmpfunc]) −− sort *IN PLACE*; if given, cmpfunc(x, y) −> −1, 0, 1


Mặc định output được định dạng để có thể dể dàng đọc . Chuổi Multi-line doc thì chuyển thành một hàng đơn , nhưng lựa chọn này có thể được thay đổi bởi đặc tả số 0 cho tham số collapse . Nếu những tên hàm dài hơn 10 kí tự . Bạn có thể đặc tả giá trị lớn hơn bởi tham số spacing để làm output dể đọc hơn


Ví dụ :

 >>> import odbchelper
 >>> info(odbchelper)
 buildConnectionString Build a connection string from a dictionary Returns string.
 >>> info(odbchelper, 30)
 buildConnectionString Build a connection string from a dictionary Returns string.
 >>> info(odbchelper, 30, 0)
 buildConnectionString Build a connection string from a dictionary
 Returns string.

Using Optional and Named Arguments

[sửa]

Python cho phép tham số hàm có giá trị mặc định . Nếu hàm được gọi mà không có tham số , tham số sẽ lấy giá trị mặc định . Xa hơn , tham số có thể được đặc tả trong bất cứ thứ bật với việc sử dụng tên tham số . Thủ tục lưu trử trong SQL Server transact/SQL có thể làm điều này .


Đây là một ví dụ về info , một hàm với hai tham số chọn :

def info(object , spacing = 10 , collapse = 1 ) :


Example Những cách gọi info hợp lệ

 info(odbchelper)
 info(odbchelper , 12 ) 
 info(odbchelper, collapse=0)
 info(spacing=15, object=odbchelper)


  • Với duy nhất một tham số , spacing và collapse lấy giá trị mặc định là 10 và 1 .
  • Với 2 tham số , collapse lấy giá trị mặc định .
  • Do đặt tên collapse = 0 , nên collapse sẽ có tra trị là 0 , bất chấp thứ tự . còn spacing có giá trị là mặc định .
  • Ngay cả tham số được đòi hỏi ( giống object ) có thể được đặt tên , và tham số được đặt tên có thể xuất hiện ở bất cứ đâu .


Using type , str , dir , and Other Built - In Functions

[sửa]

Python có một tập hợp nhỏ extremely các hàm hữu dụng . Tất cả hàm được tách ra vào trong các modules . Điều này là một quyết định thiết kế tỉnh táo , để giữ core language trở nên phồng lên giống bất cứ ngôn ngữ kịch bản khác ( cough cough , Visual basic ) .

The type function

[sửa]

Hàm type trả về kiểu giá trị của bất kì đối tượng tùy thích nào . Các lọai khả thi , thì được liệt kê trong types module .


Vídụ : Introducing type

 >>> type(1)
 <type 'int'>
 >>> li = []
 >>> type(li)
 <type 'list'>
 >>> import odbchelper
 >>> type(odbchelper)
 <type 'module'>
 >>> import types
 >>> type(odbchelper) == types.ModuleType
 True
  • type lấy bất cứ thứ gì , và trả về kiểu dữ liệu của nó . Integers , strings , lists , dictionaries ,...
  • type lấy một giá trị variable và trả về kiểu dữ liệu của nó .
  • type cũng có thể làm việc trong những modules .
  • bạn có thể sử dụng hằng trong module types để so sánh lọai đối tượng .

The str Function

[sửa]

Ví dụ : Introducing str

 >>> str(1)
 '1'
 >>> horsemen = ['war', 'pestilence', 'famine']
 >>> horsemen
 ['war', 'pestilence', 'famine']
 >>> horsemen.append('Powerbuilder')
 >>> str(horsemen)
 "['war', 'pestilence', 'famine', 'Powerbuilder']"
 >>> str(odbchelper)
 "<module 'odbchelper' from 'c:\\docbook\\dip\\py\\odbchelper.py'>"
 >>> str(None)
 'None'
  • Trong kiểu dử liệu đơn giản giống số nguyên . Bạn sẽ mong chờ str làm việc , bởi vì hầu như mỗi ngôn ngữ có một hàm để chuyển số nguỵên thành một chuỗi .
  • Dù sao đi nữa , str làm việc trên bất kì đối tượng của bất cứ lọai nào . Ở đây nó làm việc trên danh sách .
  • str cũng làm việc trên modules . Chú ý rằng sự biểu diễn chuỗi của module bao gồm pathname của module trên disk .


Ví dụ : Introducing dir

 >>> li = []
 >>> dir(li)
 ['append', 'count', 'extend', 'index', 'insert',
 'pop', 'remove', 'reverse', 'sort']
 >>> d = {}
 >>> dir(d)
 ['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']
 >>> import odbchelper
 >>> dir(odbchelper)
 ['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']


  • li là một danh sách , vì vật dir(li) trả về một danh sách của tất cả các phương thực của danh sách. Chú ý rằng danh sách được trả về chứa tên cửa phương thức như là chuỗi , không phải là phương thức của chúng .
  • d là một thư mục, vì vậy dir(d) trả về một danh sách của tên các phương thức thư mục .
  • Điều này thật sự kích thích . odbchelper là một module , vì vậy dir(odbchelper) trả về một danh sách của tất cả các định nghĩa trong module .


Ví dụ : Introducing callable

 >>> import string
 >>> string.punctuation
 '!"#$%&\'()*+,−./:;<=>?@[\\]^_`{|}~'
 >>> string.join 
 <function join at 00C55A7C>
 >>> callable(string.punctuation)
 False
 >>> callable(string.join)
 True
 >>> print string.join.__doc__
 join(list [,sep]) −> string
  Return a string composed of the words in list, with
  intervening occurrences of sep. The default separator is a
  single space.
  • Những hàm trong module string thì phản kháng ( mặc dù nhiều người vẫn còn dùng hàm join ). Nhưng module chứa nhiều hằng có ích giống như string.punctuation , chứa tất cả kí tự chấm câu tiêu chuẩn .
  • string.join là hàm dùng để join một danh sách các chuỗi .
  • string.punctuation thì không thể được gọi ; nó là một chuỗi ( Một String có phương thức callable ,nhưng chuỗi của chính nó thì không có ) .
  • string.join is callable , nó là một hàm lấy hai tham số .
  • Bất cứ đối tượng callables có thể có một doc string . Sử dụng hàm callable trên mỗi một thuộc tính của đối tượng , bạn có thể xác định , thuộc tính bạn quan tâm , và cái nào mà bạn muốn bỏ qua .

Built-In Function

[sửa]

type, str, dir, and all the rest of Python's built−in functions được nhóm thành một modules đặc biệt được gọi là __builtin__. Bạn có thể nghĩ rằng python tự động thực thi " from __builtin__ import * " on startup . Ưu điểm của điều này là bạn có thể truy câp tất cả hàm built-in và thuộc tính như một nhóm bởi lấy thông tin về __builtin__ module .


Ví dụ : Built−in Attributes and Functions

 >>> from apihelper import info
 >>> import __builtin__
 >>> info(__builtin__, 20)
 
 ArithmeticError Base class for arithmetic errors.
 AssertionError Assertion failed.
 AttributeError Attribute not found
 EOFError Read beyond end of file.
 EnvironmentError Base class for I/O related errors.
 Exception Common base class for all exceptions.
 FloatingPointError Floating point operation failed.
 IOError I/O operation failed.


Getting Object References with getattr

[sửa]

Bạn đã biết về hàm và đối tượng trong python . Bạn khôn biết điều gì có thể tham chiếu tới một hàm mà không cần biết nó đang chạy , bằng sử dụng getattr function .


Ví dụ Introducing getattr

 >>> li = ["Larry", "Curly"]
 >>> li.pop
 <built−in method pop of list object at 010DF884>
 >>> getattr(li, "pop")
 <built−in method pop of list object at 010DF884>
 >>> getattr(li, "append")("Moe")
 >>> li
 ["Larry", "Curly", "Moe"]
 >>> getattr({}, "clear")
 <built−in method clear of dictionary object at 00F113D4>
 >>> getattr((), "pop")
 
   Traceback (innermost last):
   File "<interactive input>", line 1, in ?
   AttributeError: 'tuple' object has no attribute 'pop'


  • Điều này lấy một tham chiếu tới phương thức pop trên danh sách . Chú ý rằng điều này không gọi phương thức pop . Nếu vậy sẽ là li.pop() . Đây là phương thức của chính nó .
  • Điều này cũng trả về một tham chiếu tới phương thức pop , tên phương thức được miêu tả như là một chuỗi , tham số tới hàm getattr . getattr là một hàm built−in hữu dụng không thể ngờ cái trả về bất cứ thuộc tính của bất cứ đối tượng . Trong trường hợp này , đối tượng là một danh sách , và thuộc tính là phương thức pop .
  • Giá trị trả về của getattr là một phương thức .
  • getattr cũng làm việc trên từ điển .
  • Trong lý thuyết , getattr sẽ làm việc trên tuples , trừ ra tuples không có phương thức , vì vậy getattr sẽ ném một ngọai lệ , không vấn đề gì về tên thuộc tính mà bạn đưa .

getattr with Modules

[sửa]

Ví dụ . The getattr Function in apihelper.py

 >>> import odbchelper
 >>> odbchelper.buildConnectionString
 <function buildConnectionString at 00D18DD4>
 >>> getattr(odbchelper, "buildConnectionString")
 <function buildConnectionString at 00D18DD4>
 >>> object = odbchelper
 >>> method = "buildConnectionString" 
 >>> getattr(object, method)
 <function buildConnectionString at 00D18DD4>
 >>> type(getattr(object, method))
 <type 'function'>
 >>> import types
 >>> type(getattr(object, method)) == types.FunctionType
 True
 >>> callable(getattr(object, method))
 True


  • Điều này trả về một tham chiếu tới hàm buildConnectionString trong module odbchelper
  • Sử dụng getattr, bạn có thể tham chiếu tới hàm . getattr(object,"attribute") thì tương ứng với object.attribute. Nếu đối tượng có một module , thì thuộc tính có thể được đinh nghĩa bất kỳ trong module : a function, class, or global variable.
  • Và điều này là cái gì bạn thật sự dùng trong hàm info. Đối tượng được truyền vào trong hàm như tham số . Phương thức là một chuổi , thì cùng tên với phương thức hay hàm .

method is a string which is the name of a method or function.

  • Trong trường hợp này , phương thức là tên của một hàm.

getattr As a Dispatcher

[sửa]

Ví dụ : Creating a Dispatcher with getattr

 import statsout
 def output(data, format="text"):
 output_function = getattr(statsout, "output_%s" % format)
 return output_function(data)
  • Hàm output đòi hỏi một tham số ( data ) , và một tham số chon lựa ( format ). Nếu format thì không được truyền , nó sẽ mặc định là text .
  • Giá trị là một tham chiếu to hàm thích hợp từ module statsout.


Ví dụ : getattr Default Values


 import statsout
 def output(data, format="text"):
    output_function = getattr(statsout, "output_%s" % format, statsout.output_text)
    return output_function(data)


  • Gọi Hàm này is đảm bảo để làm việc , bởi vì bạn thêm ba tham số để gọi getattr .
  • Tham số thứ ba là một giá trị mặc định và được trả về . Nếu thuộc tính hay phương thức đặc tả bởi tham số thứ hai thì không tìm thấy .

Filtering List

[sửa]

Python có khả năng ánh xạ danh sách vào trong danh sách khác .

Đây là cú pháp lọc danh sách : [mapping−expression for element in source−list if filter−expression]


Ví dụ : Introducing List Filtering

  >>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
  >>> [elem for elem in li if len(elem) > 1]
  ['mpilgrim', 'foo'] 
  >>> [elem for elem in li if elem != "b"]
  ['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
  >>> [elem for elem in li if li.count(elem) == 1]
  ['a', 'mpilgrim', 'foo', 'c']


  • Biểu thức ánh xạ ở đây thì đơn giản ( nó chỉ trả về giá trị của mỗi phần tử ), vì vậy nên tập trung vào biểu thức lọc ( filter ). Trong khi vòng lặp Python thông quan danh sách , nó chạy qua mỗi phần tử trong mảng và đưa vào biểu thức lọc. Nếu biểu thức lọc là true , phần tử được ánh xạ và kết quả của biểu thức ánh xạ là danh sách .

The Peculiar Nature of and and or

[sửa]

Trong Python , and va or and được biểu diển boolean luận lí , nhưng chúng không trả về giá trị boolean . Thực tế , chúng trả về một trong những giá trị thực mà chúng đang so sánh .


Ví dụ : Introducing and

  >>> 'a' and 'b'
  'b'
  >>>  and 'b'
  
  >>> 'a' and 'b' and 'c'
  'c'


  • Khi dùng and , giá trị được ước lượng trong một ngữ cảnh luận lí ( in a boolean context ) từ trái sang phải . 0, , [], (), {}, và None là false trong ngử cảnh boolean ; mỗi thứ khác đều là true . Mặc định , ví dụ classes là true trong boolean context , nhưng bạn không thể định nghĩa phương thức đặc tả trong lớp của anh để làm ví dụ cho false
  • Nếu bất kỳ giá trị là false trong boolean context , và trả về giá trị đầu tiên là false . Trong trường hợp này , là giá trị false đầu tiên .
  • Tất cả giá trị là true , vì vậy trả về giá trị cuối là , 'c'.


Ví dụ : Introducing or

 >>> 'a' or 'b'
 'a'
 >>>  or 'b'
 'b'
 >>>  or [] or {}
 {}
 >>> def sidefx():
 ... print "in sidefx()"
 ... return 1
 >>> 'a' or sidefx()
 'a'


  • Khi dùng or , giá trị thì ước lượng trong boolean context từ trái sang phải . Nếu bất cứ giá trị là true hoặc trả về giá tri đó lập tức . Trong trường hợp này , 'a' là giá trị true đầu tiên .
  • Ta có là false, rồi 'b' là true, và trả về 'b'.
  • Nếu tất cả giá trị là false hoặc trả về giá trị cuối . Ta có là false , rồi [] là false, rồi {} cũng là false , sẽ trả về giá trị {} .
  • Chú ý rằng or ước lương các giá trị đến khi or tìm thấy một cái là true trong boolean context, và sau đó nó bỏ quả và nghĩ . Điều này quan trong nếu vài giá trị có thể có hiệu ứng bên cạnh . sidefx hàm thì không bao giờ được gọi , bởi vì ước lượng 'a' is true, và trả về 'a'lập tức.

Using the and−or Trick

[sửa]

Ví dụ : Introducing the and−or Trick

 >>> a = "first"
 >>> b = "second"
 >>> 1 and a or b
 'first'
 >>> 0 and a or b
 'second' 


  • Cú pháp này giống biểu thức " bool ? a : b " trong C . Tòan bộ biểu thức được ước lương từ trái sang phải , vì vậy and được mặc đinh đầu tiên .
  • 0 và 'first' ước lượng là false , và sau đó 0 or 'second' ước lượng 'second'.


Ví dụ : When the and−or Trick Fails

 >>> a = ""
 >>> b = "second"
 >>> 1 and a or b
 'second'
  • a là một chuỗi rỗng , Python cân nhắc false trong một boolean context, 1 và ược lượng , và

sau đó hoặc 'second' mặc định 'second'.

Vi dụ : Using the and−or Trick Safely

 >>> a = ""
 >>> b = "second"
 >>> (1 and [a] or [b])[0]
 
  • Khi [a] không là một danh sách rổng , nó thì không bao giờ false . Ngay cả nếu a là 0 hoặc vài giá trị false khác , danh sách [a] là true bởi vì nó có một phần tử .

Using lambda functions

[sửa]

Python hổ trợ một cú pháp quan trọng mà để bạn định nghĩa một hàng , hàm nhỏ trên fly . Được mượn từ Lisp, Những cái này được gọi là hàm lambda mà có thể được dùng bất cứ đâu khi một hàm được đòi hỏi .


Ví dụ : Introducing lambda Functions

 >>> def f(x):
 ... return x*2
 ...
 >>> f(3)
 6
 >>> g = lambda x: x*2
 >>> g(3)
 6
 >>> (lambda x: x*2)(3)


  • Đây là một hàm lambda , trông giốn như một hàm thông thường trên nó . Chú ý cú pháp tóm tắt ở đây : Không có dấu ngoặc đơn quanh danh sách tham số , và từ khóa return bỏ qua . Dù vậy , hàm không tên , nhưng nó có thể được gọi thông qua biến nó assign.
  • Bạn có thể sử dụng hàm lambda không cần assign một biến .

Real−World lambda Functions

[sửa]

Here are the lambda functions in apihelper.py:

 processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s) 

Ví dụ : split With No Arguments

 >>> s = "this is\na\ttest"
 >>> print s 
 this is
 a test
 >>> print s.split()
 ['this', 'is', 'a', 'test']
 >>> print " ".join(s.split())
 'this is a test'


  • Đây là một chuỗi nhiều dòng , được định nghĩa bởi kí tự escape thay vì ba đấu ngoặc
  • split không có bất cứ tham số . Vì vậy tách dựa trên ' ', '\n', '\t' .
  • Bạn có thể sử dụng chuổi " " nối chuổi vừa được tách .


Hàm info thật sự làm với 3 hàm lambda , splits và and-or tricks ?

 processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

Putting it all together

[sửa]

This is the meat of apihelper.py:

 print "\n".join(["%s %s" %
                 (method.ljust(spacing),
                  processFunc(str(getattr(object, method).__doc__)))
                  for method in methodList])


Ví dụ : Getting a doc string Dynamically

 >>> import odbchelper
 >>> object = odbchelper
 >>> method = 'buildConnectionString'
 >>> getattr(object, method)
 <function buildConnectionString at 010D6D74>
 >>> print getattr(object, method).__doc__  
 Build a connection string from a dictionary of parameters.
 Returns string.


  • Trong hàm info , object là đối tượng bạn đang lấy sự giúp đở , truyền trong như một tham số .
  • Trong khi bạn đang lặp xuyên qua danh sách , phương thức là tên của phương thức hiện tại .
  • Sử dụng hàm getattr , bạn dang lấy một tham chiếu tới phương thức của đối tương trong module .
  • Bây giờ là phương thức in doc string thì dể dàng .


Ví dụ. Introducing ljust

 >>> s = 'buildConnectionString'
 >>> s.ljust(30)
 'buildConnectionString '
 >>> s.ljust(20)
 'buildConnectionString'


  • ljust thêm vào chuổi với khỏang trống với độ dài được truyền .
  • Nếu độ dài được đưa vào thì nhỏ hơn độ dài của chuỗi , ljust sẽ đơn giản trả về chuỗi không bị thay đổi .

Ví dụ : Printing a List

 >>> li = ['a', 'b', 'c']
 >>> print "\n".join(li)
 a
 b
 c


  • Đây là cách hửu dụng để gỡ rối với trick . Và trong python , bạn luôn luôn làm việc với danh sách .

Bây giờ bạng có thể hiểu dòng code sau .

 print "\n".join(["%s %s" %
                  (method.ljust(spacing),
                   processFunc(str(getattr(object, method).__doc__)))
                   for method in methodList])

Summary

[sửa]
  • Định nghĩa và gọi một hàm với tham số tùy chọn và xác định .
  • Sử dụng str để cưởng bức bất cứ giá trị tùy ý nào vào trong biểu diển chuổi .
  • Sử dụng getattr để lấp tham chiếu tới hàm và thuộc tính động .
  • Mở rộng danh sách , cú pháp để lọc danh sách .
  • Nhận diện and−or trick và dùng nó an tòan .
  • Định nghĩa hàm lambda.
  • Assigning functions vào biến và gọi hàm bằng tham chiếu qua biến đó .