Daily Archives: 26/01/2016

Python – File

Trong phần này chúng ta sẽ tìm hiểu về cách đọc ghi file trong Python.

Hệ thống nhập xuất chuẩn

Trong Python có 3 luồng nhập xuất là luồng input, luồng output và luồng error. Luồng input là luồng nhập, tất cả các dữ liệu đi vào chương trình đều đi qua đường này, luồng này mặc định được kết nối giữa chương trình với bàn phím. Luồng output là luồng xuất, làm nhiệm vụ đưa dữ liệu ra ngoài, mặc định gắn với màn hình console (trên Windows là cmd – Command Prompt, trên Linux là Terminal). Luồng error là luồng báo lỗi, luồng này đưa các thông báo lỗi ra ngoài, mặc định cũng gắn với màn hình console.

Luồng input

Đây là dòng dữ liệu đi vào chương trình.

import sys


print ('Enter your name: ',)

name = ''

while True:
   c = sys.stdin.read(1)
   if c == '\n':
      break
   name = name + c

print ('Your name is:', name)

Để làm việc với dòng nhập xuất thì chúng ta phải import module sys. Trong module này có đối tượng stdin với phương thức read(), phương thức này đọc các kí tự trong luồng nhập. Trong ví dụ trên, chúng ta in ra dòng chữ “Enter your name:”, sau đó cho một vòng lặp chạy, mỗi lần lặp chúng ta gọi phương thức read() trên để đọc từng kí tự vào từ luồng nhập và kiểm tra nếu kí tự vào là kí tự Enter thì thoát vòng lặp. Kí tự enter có kí hiệu là \n.

Enter your name: Jan
 Your name is: Jan

Ngoài phương thức read() ra còn có các hàm làm nhiệm vụ tương tự là input() và raw_input() .

Hàm input() in ra dòng thông báo, đọc dữ liệu vào và đánh giá  dữ liệu.

data = input('Enter expression: ')

print ('You have entered:', data)
Enter expression: 3*3
You have entered: 9

Hàm raw_input() cũng tương tự như hàm input().

Luồng output

Luồng output là luồng dữ liệu đi ra khỏi chương trình.

import sys

sys.stdout.write('Honore de Balzac, Father Goriot\n')
sys.stdout.write('Honore de Balzac, Lost Illusions\n')

Trong ví dụ trên, chúng ta in các đoạn text ra màn hình bằng phương thức write().

Honore de Balzac, Father Goriot
Honore de Balzac, Lost Illusions

Hàm print() mà chúng ta dùng lâu nay thực chất là nó gọi tới phương thức write() của đối tượng stdout.

print ('Honore de Balzac, The Splendors and Miseries of Courtesans')
print ('Honore de Balzac, Gobseck')

Chuyển hướng luồng nhập xuất vào file

Như đã nói ở đầu bài, luồng nhập xuất mặc định được gắn với màn hình và bàn phím. Tuy nhiên chúng ta có thể chuyển hướng chúng để làm việc với file.

import sys


f = open('output.txt', 'w')
sys.stdout = f

print ('Lucien')
sys.stdout.write('Rastignac\n')
sys.stdout.writelines(['Camusot\n', 'Collin\n'])

sys.stdout = sys.__stdout__

print ('Bianchon')
sys.stdout.write('Lambert\n')

Trong đoạn code trên, chúng ta chuyển hướng stdout từ màn hình sang file.

Bianchon
Lambert
Lucien 
Rastignac 
Camusot 
Collin

Hàm open

Hàm open() được dùng để mở file trong hệ thống.

open(filename, [mode='r'], [bufsize])

Hàm này nhận ba tham số đầu vào, tham số thứ nhất là tên file, tham số thứ 2 là chế độ mở, tham số thứ 3 là kích thước bộ đệm. Chế độ mở file ở đây chỉ định cách mà file được mở. Có các chế độ như mở để đọc, ghi, ghi đè… Tham số bộ đệm là tham số tùy chọn, tức là bạn không cần đưa tham số này vào, nhưng thường thì bạn cũng không cần quan tâm đến tham số này làm gì.

Dưới đây là danh sách các chế độ mở file:

Mode Meaning
r Đọc dữ liệu kiểu text
rb Đọc dữ liệu kiểu nhị phân
w Ghi dữ liệu kiểu text
wb Ghi dữ liệu nhị phân
a Ghi thêm vào cuối file
+ Ghi đè

Đoạn code đưới dây đọc nội dung một file.

f = open('ifyouwantme', 'r')

for line in f:
   print (line,)

f.close()

Chúng ta mở file ở chế độ đọc. Sau đó duyệt qua toàn bộ nội dung file bằng vòng lặp for. Cuối cùng chúng ta đóng file này lại.

Are you really here or am I dreaming
I can't tell dreams from truth 
for it's been so long since I have seen you
I can hardly remember your face anymore 

When I get really lonely
and the distance causes our silence
I think of you smiling 
with pride in your eyes a lover that sighs 

...

Trong ví dụ dưới đây, chúng ta cũng đọc file nhưng dùng phương thức readline().

f = open('ifyouwantme', 'r')

while True:
   line = f.readline()
   if not line: break
   else: print (line,)

f.close()

Ngoài ra chúng ta có phương thức readlines() (có thêm chữ s sau readline), phương thức này sử dụng đơn giản vì mỗi lần gọi, phương thức này đọc toàn bộ nội dung file vào bộ nhớ, cũng vì thế nên chúng ta nên hạn chế sử dụng phương thức này với các file có kích thước lớn.

f = open('ifyouwantme', 'r')

contents = f.readlines()

for i in contents:
   print (i,)

f.close()

Trong ví dụ tiếp theo, chúng ta sẽ ghi nội dung vào file.


text = """Incompatible, it don't matter though
'cos someone's bound to hear my cry
Speak out if you do
You're not easy to find\n"""


f = open('strophe.txt', 'w')
f.write(text)

f.close()

Để ghi file thì chỉ đơn giản là mở file ở chế độ w, sau đó dùng phương thức write() để ghi, nếu file đã tồn tại thì nội dung file sẽ bị ghi đè.

Incompatible, it don't matter though
'cos someone's bound to hear my cry
Speak out if you do
You're not easy to find

Module pickle

Bây giờ chúng ta sẽ đọc và ghi file theo kiểu dữ liệu nhị phân, ví dụ về các dạng dữ liệu nhị phân là hình ảnh, nhạc, phim… ngay cả các đoạn text thông thường cũng có cách để ghi theo kiểu nhị phân. Trong ví dụ dưới đây, chúng ta sẽ ghi dữ liệu của một đối tượng vào file. Để ghi dữ liệu dạng nhị phân thì chúng ta dùng tới module pickle. Khi ghi lên file, pickle sẽ chuyển các đoạn text thành các dạng kí hiệu, khi đọc, nó sẽ chuyển ngược lại về text cho chúng ta.


import pickle

class Person:
   def __init__(self, name, age):
      self.name = name
      self.age = age

   def getName(self):
      return self.name

   def getAge(self):
      return self.age


person = Person('Monica', 15)
print (person.getName())
print (person.getAge())

f = open('monica', 'wb')
pickle.dump(person, f)
f.close()

f = open('monica', 'r')
monica = pickle.load(f)
f.close()

print (monica.getName())
print (monica.getAge())

Trong đoạn code trên, chúng ta định nghĩa lớp Person và tạo một đối tượng với lớp này. Sau đó chúng ta ghi dữ liệu của đối tượng này vao file bằng phương thức dump(). Để đọc dữ liệu nhị phân thì chúng ta dùng phương thức load().

Monica
15
Monica
15
monica: ASCII text

 

Python – Hàm

Trong phần này chúng ta sẽ tìm hiểu về hàm trong Python.

Hàm là một đoạn lệnh trong một chương trình thực hiện một công việc nào đó. Việc dùng hàm có các lợi ích sau:

  • Giảm khối lượng mã nguồn
  • Dễ quản lý do chương trình được chia thành nhiều phần nhỏ
  • Mã nguồn trở nên sáng sủa
  • Tái sử dụng lại mã nguồn
  • Che giấu thông tin

Trong Python một hàm cũng tương đương với một đối tượng. Giá trị của hàm có thể được gán vào biến, lưu vào trong danh sách hoặc được dùng để làm tham số của các hàm khác… làm cho ngôn ngữ lập trình trở nên tinh xảo hơn.

Có hai loại hàm, thứ nhất là các hàm có sẵn ví dụ như dir(), len(), abs()… thứ hai là các hàm do chúng ta tạo ra, để tạo ra một hàm (hay còn còn là định nghĩa một hàm) thì chúng ta dùng từ khóa def.

Định nghĩa một hàm

Chúng ta định nghĩa một hàm bằng từ khóa def, phần code bên trong hàm phải thụt lùi vào.

def function():
    pass

Sau từ khóa def là tên hàm với cặp dấu ngoặc tròn () và dấu hai chấm. Bên dưới chúng ta thụt lùi vô để viết các đoạn code, phần này là phần thân hàm.

Hàm sau khi được định nghĩa xong sẽ được thực thi khi cần thiết. Trong lập trình thì chúng ta dùng từ “gọi hàm” để chỉ việc sử dụng hàm đó. Chỉ khi chúng ta gọi hàm, đoạn code bên trong thân hàm mới được thực hiện.

myfunc()

Để gọi một hàm thì chỉ đơn giản là ghi lại tên hàm đó cùng với cặp dấu ngoặc tròn ().

"""
The test.py script shows how to work with
functions in Python. 
author: PhoCode, 2016
"""

def showModuleName(): 
    print (__doc__ )

def getModuleFile(): 
    return __file__

a = showModuleName() 
b = getModuleFile() 

print (a, b)

Trong ví dụ trên, ở phần đầu chúng ta có một string giới thiệu về đoạn code trong file, đoạn string này có tác dụng giống như lời giới thiệu, mô tả về chương trình vậy. File chứa đoạn code này được gọi là module. Trong đoạn code trên, chúng ta định nghĩa hai hàm, hàm đầu tiên in ra nội dung của biến __doc__, hàm thứ hai trả về giá trị của biến __file__. Một hàm có thể có hoặc không có giá trị trả về. Nếu chúng ta không trả về một thứ gì thì mặc định Python sẽ ngầm trả về None. Hai biến __doc__ và __file__ là hai biến đặc biệt trong Python.


The test.py script shows how to work with
functions in Python. 
author: PhoCode, 2016

None C:\Users\PhoCode\test.py

Như đã nói ở trên, phần thân hàm phải viết lùi vào trong, nếu không sẽ có lỗi.


def f1():
    print ("f1()")
    
f1()
#f2()

def f2():
    print ("f2()")

Trong ví dụ trên, chúng ta định nghĩa hai hàm và gọi hai hàm đó. Nhưng một câu lệnh gọi hàm đã bị đánh dấu là chú thích vì nó được gọi trước phần định nghĩa hàm, một hàm luôn luôn phải được định nghĩa trước khi được gọi, tức là phải viết phần định nghĩa trước rồi mới đến câu lệnh gọi.

#f2()

def f2():
    print ("f2()")

Nếu muốn gọi hàm f2() thì bạn phải để câu lệnh f2() sau phần định nghĩa hàm. Nếu không sẽ báo lỗi.

Vị trí của hàm

Một hàm có thể được định nghĩa bên trong một module, một lớp hoặc bên trong một hàm khác. Hàm được định nghĩa bên trong một lớp được gọi là phương thức.


class Some:

    @staticmethod  
    def f():
        print ("f() method")

def f():
    print ("f() function")
    
def g():
    def f():
        print ("f() inner function")
    f()        
        
Some.f()
f()
g()

Trong ví dụ trên, chúng ta định nghĩa hàm ở những vị trí khác nhau.

class Some:

    @staticmethod  
    def f():
        print ("f() method")

Đoạn code trên định nghĩa một phương thức tĩnh với nhờ vào chỉ thị @staticmethod trong lớp Some.

def f():
    print ("f() function")

Đoạn code trên định nghĩa một hàm bình thường.

def g():
    def f():
        print ("f() inner function")
    f()   

Đoạn code trên định nghĩa hàm f() bên trong hàm g(), hàm được định nghĩa bên trong một hàm khác được gọi là hàm nội (inner function).

Some.f()
f()
g() 

Chúng ta gọi phương thức tĩnh bằng cách ghi tên lớp, sau đó là dấu chấm và tên phương thức cùng với cặp dấu ngoặc tròn (). Các hàm bình thường được gọi bằng cách ghi tên hàm với cặp dấu ngoặc tròn ().

f() method
f() function
f() inner function

Đối tượng hàm

Bản chất của hàm trong Python là các đối tượng. Chúng được xử lý như các đối tượng tạo ra từ các lớp.


def f():
    """This function prints a message """
    print ("Today it is a cloudy day")
    
print (isinstance(f, object))
print (id(f))
    
print (f.__doc__)
print (f.__name__)

Đoạn code trên kiểm tra tính đối tượng của hàm.

def f():
    """This function prints a message """
    print ("Today it is a cloudy day")

Đoạn code trên định nghĩa hàm f(). Hàm này in một string là màn hình. Ngoài ra hàm này còn có một đoạn string giới thiệu ở đầu nữa.

print (isinstance(f, object))

Hàm isinstance() có tác dụng kiểm tra xem hàm f() có phải là một đối tượng của lớp object hay không. Lớp object là lớp cơ sở, mọi lớp trong Python đều kế thừa từ lớp này.

print (id(f))

Mỗi đối tượng trong Python đều có một id. Hàm id() trả về id của đối tượng đó.

print (f.__doc__)
print (f.__name__)

Tất cả các đối tượng đều chứa biến bên trong nó, biến trong đối tượng được gọi là các thuộc tính. Hai thuộc tính __doc____name__ là hai thuộc tính có sẵn có các đối tượng trong Python.

True
3077407212
This function prints a message 
f

Các đối tượng có thể được lưu trữ trong các danh sách hoặc làm tham số cho các hàm khác.


def f():
    pass

def g():
    pass
  
def h(f):
    print (id(f))
  
a = (f, g, h)

for i in a:
    print (i)
    
h(f)
h(g)

Ở trên chúng ta định nghĩa 3 hàm. Sau đó chúng ta lưu chúng trong một tuple và đưa vào tham số của một hàm.

a = (f, g, h)

for i in a:
    print (i)

Trong đoạn code trên, chúng ta đưa 3 đối tượng vào một tuple và duyệt tuple đó.

h(f)
h(g)

Hai dòng trên chúng ta đưa hàm f() và g() làm tham số của hàm h().

<function f at 0xb7664fb4>
<function g at 0xb766c1b4>
<function h at 0xb766c3ac>
3076935604
3076964788

Từ khóa return

Hàm được tạo ra để thực hiện các công việc nào đó. Thường thì các công việc này phải có một kết quả nào đó. Ví dụ bạn viết một hàm làm công việc là tính tổng của một dãy số, sau khi khai báo tên hàm, bạn khai báo biến để lưu giá trị tổng rồi duyệt qua một danh sách cho trước để tính tổng rồi lưu vào biến tổng đó, nhưng khi kết thúc hàm thì biến tính tổng đó bị xóa, bạn chẳng thể nào lấy được biến tổng ở ngoài hàm đó nữa. Lúc này bạn cần dùng đến từ khóa return, từ khóa return có tác dụng “trả về” một giá trị của một hàm. Một hàm có thể có hoặc không có từ khóa return, nếu không có thì Python mặc định ngầm trả về một đối tượng None.


def showMessage(msg):
    print (msg)

def cube(x):
    return x * x * x   
   
x = cube(3)    
print (x)

showMessage("Computation finished.")
print (showMessage("Ready."))

Trong đoạn code trên, chúng ta định nghĩa hai hàm. Một hàm có return, một hàm không.

def showMessage(msg):
    print (msg)

Hàm showMessage() không trả về mọt giá trị gì mà chỉ in ra một dòng string.

def cube(x):
    return x * x * x

Hàm cube() thực hiện tính lập phương của một số và trả về giá trị của phép tính này.

x = cube(3) 

Ở dòng code trên, chúng ta gọi hàm cube(). Như đã nói ở trên hàm này sẽ trả về một giá trị, chúng ta lưu lại giá trị này bằng cách gán nó cho biến x.

showMessage("Computation finished.")

Ở dòng trên chúng ta gọi hàm showMessage() có tham số đầu vào là một string. Hàm này chỉ có nhiệm vụ in đoạn string ra màn hình chứ không trả về gì cả.

print (showMessage("Ready."))

Dòng code trên in ra hai lần, vì trong hàm showMessage() đã có lệnh in ra một string. Hàm này lại được làm đối số trong một hàm print() khác, mà vì hàm này không có câu lệnh return nào nên ngầm trả về đối tượng None nên hàm print() ở ngoài sẽ in ra None.

Định nghĩa lại hàm

Trong Python bạn có thể định nghĩa lại một hàm đã được định nghĩa sẵn, mặc dù làm thế cũng không có ý nghĩa mấy và thực tế thì trong các ngôn ngữ khác bạn không được phép làm điều này.


from time import gmtime, strftime


def showMessage(msg):
    print (msg)
        
showMessage("Ready.")

def showMessage(msg):
    print (strftime("%H:%M:%S", gmtime()),)
    print (msg)
    
showMessage("Processing.")  

Trong ví dụ trên chúng ta định nghĩa hàm showMessage() hai lần.

from time import gmtime, strftime

Ở dòng trên chúng ta import hàm gmtime(), strftime() từ module time.

def showMessage(msg):
    print (msg )       

Đây là hàm showMessage() được định nghĩa lần thứ nhất.

def showMessage(msg):
    print (strftime("%H:%M:%S", gmtime()),)
    print (msg)

Đoạn code trên là phần định nghĩa hàm showMEssage() lần thứ hai. Lần này chúng ta sử dụng một số hàm lấy thời gian trong module time.

Ready.
23:49:33 Processing.

Tham số cho hàm

Ví dụ khi bạn cần một hàm làm công việc tính tổng của một dãy số, hàm đó sẽ cần biết phải tính dãy số nào chứ? Và dãy số mà bạn “đưa” cho hàm để nó làm công việc tính toán gọi là tham số. Vậy là bâu giờ bạn biết được quá trình làm việc của một hàm thông thường rồi. Ban đầu hàm nhận vào các tham số, sau đó xử lý chúng và return lại kết quả cho chúng ta.

Untitled


def C2F(c):
    return c * 9/5 + 32

print (C2F(100))
print (C2F(0))
print (C2F(30))

Trong đoạn code trên, chúng ta viết hàm chuyển đổi nhiệt độ từ Celsius sang Fahrenheit. Hàm này nhận vào tham số là nhiệt độ ở Celsius.

212
32
86

Bạn có thể đặt giá trị mặc định cho các tham số, giá trị mặc định sẽ được sử dụng nếu bạn không đưa vào một tham số nào khi gọi hàm.


def power(x, y=2):
    r = 1
    for i in range(y):
       r = r * x
    return r

print (power(3))
print (power(3, 3))
print (power(5, 5))

Ở trên chúng ta định nghĩa hàm lấy lũy thừa. Hàm này nhận hai tham số, trong đó tham số y có giá trị mặc định là 2.

9
27
3125

Truyền tham số kiểu tham chiếu

Khi bạn đưa các tham số vào một hàm, bên trong hàm sẽ tạo một biến khác và copy giá trị của tham số truyền vào vào biến mới này, và khi kết thúc hàm thì biến này sẽ bị xóa, tham số kiểu này được gọi là tham trị. Tuy nhiên bạn có thể đưa chính biến ở ngoài vào, hàm sẽ thực hiện xử lý trên biến này luôn chứ không tạo biến mới nữa, tham số kiểu này được gọi là tham chiếu. 

def f(x):
 x = "Bonjour"
 
str = "Hello"
print (str)

f(str)

print(str)

Trong ví dụ trên, chúng ta định nghĩa hàm f(), hàm này thay đổi giá trị truyền vào thành chuỗi “Bonjour”, tuy nhiên vì là truyền theo kiểu tham trị, nên khi đưa một biến vào hàm này, giá trị của biến đó cũng không thay đổi.

Hello
Hello

Mặc định các tham số có kiểu dữ liệu dạng danh sách như list, tuple, dictionary thì các tham số này là tham chiếu.


n = [1, 2, 3, 4, 5]

print ("Original list:", n)

def f(x):
    x.pop()
    x.pop()
    x.insert(0, 0)
    print ("Inside f():", x) 
    
f(n)    

print ("After function call:", n)

Trong ví dụ trên, chúng ta truyền vào hàm f() list n, sau khi hàm này xử lý xong thì list này cũng thay đổi do hàm này xử lý trên list chứ không tạo list mới.

Original list: [1, 2, 3, 4, 5]
Inside f(): [0, 1, 2, 3]
After function call: [0, 1, 2, 3]

Biến toàn cục và biến cục bộ

Tiếp theo chúng ta tìm hiểu về biến toàn cục và biến cục bộ.


name = "Jack"

def f():
   name = "Robert"
   print ("Within function", name)

print ("Outside function", name)
f()

Một biến được định nghĩa bên trong một hàm chỉ có thể nhìn thấy bên trong hàm đó và được gọi là biến cục bộ.

Outside function Jack
Within function Robert

name = "Jack"

def f():
   print ("Within function", name)

print ("Outside function", name)
f()

Các biến được định nghĩa ngoài hàm, nói chính xác hơn là không nằm trong hàm nào thì được gọi là biến toàn cục. Biến này có thể được nhìn thấy ở bất cứ đâu.

Outside function Jack
Within function Jack

Tuy nhiên bạn có thể làm cho một biến cục bộ trở thành biến toàn cục bằng từ khóa global.


name = "Jack"

def f():
   global name 
   name = "Robert"
   print ("Within function", name)


print ("Outside function", name)
f()
print ("Outside function", name)

Trong đoạn code trên, chúng ta chỉ định cho biến name bên trong hàm là biến toàn cục, tức là bay giờ biến name đó chính là biến name đã được định nghĩa ở ngoài hàm.

global name 
name = "Robert"

Ở đoạn code trên, chúng ta dùng từ khóa global để làm cho một biến cục bộ trở thành biến toàn cục.

Outside function Jack
Within function Robert
Outside function Robert