Author Archives: Phở Code

Python – Package

Trong bài này chúng ta sẽ tìm hiểu về gói (Package) trong Python.

Một package đơn giản là một thư mục chứa các module có liên quan với nhau, trong thư mục này có một file đặc biệt tên là __init__.py.

Như trong bài trước chúng ta đã biết trong Python có các cách sau để quản lý code:

  • Dùng hàm
  • Dùng lớp
  • Dùng module
  • Dùng package

Nếu chương trình của chúng ta đủ lớn (cỡ hàng trăm module) thì chúng ta nên dùng package.

Để tạo một package thì bạn làm những bước sau đây:

  • B1: Tạo một thư mục với tên package mà bạn muốn đặt
  • B2: Trong thư mục đó tạo một file có tên __init__.py
  • B3: Đặt các module mà bạn viết vào thư mục đó

Bất cứ thư mục nào chứa file __init__.py sẽ sẽ trở thành một package của Python.

Ví dụ: mình tạo một folder với tên constantstrong file này mình tạo file __init__.py và một module có tên names (file có tên names.py)

test_package.py
constants/
          __init__.py
          names.py 
print ("Package names initialized!")
names = ('Jack', 'Jessica', 'Robert', 'Lucy', 'Tom')

Vậy là bạn đã tạo xong package constants rồi. Bây giờ chúng ta sẽ tạo một file script Python ở ngoài để dùng thử.

from constants import names
print (names.names)

Để sử dụng package thì bạn dùng câu lệnh import như dùng với module bình thường.

Package names initialized!
('Jack', 'Jessica', 'Robert', 'Lucy', 'Tom')

Bạn cũng có thể tạo một package trong một package hay còn gọi là các package con.

test_package.py
constants/
          __init__.py
          names.py 
          numbers/
                   __init__.py
                   integers.py

Trong ví dụ trên chúng tạo package numbers trong package constants. Bên trong package numbers có một module tên là integers.

print ("Package constants.numbers initialized")

Các file __init__.py bạn có thể để trống chứ không cần ghi gì trong đó cả.

integers = (2, 3, 45, 6, 7, 8, 9)

from constants import names
from constants.numbers import integers

print (names.names)
print (integers.integers)

Để import package con thì bạn dùng dấu chấm.

Package constants initialized!
Package constants.numbers initialized!
('Jack', 'Jessica', 'Robert', 'Lucy', 'Tom')
(2, 3, 45, 6, 7, 8, 9)

 

Python – Module

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

Module trong Python rất đơn giản, đó là các file chứa code python có đuôi mở rộng là .py. Dùng module là một cách tuyệt vời để quản lý code Python, ngoài module ra thì chúng ta còn có các cách sau:

  • Dùng Hàm
  • Dùng Lớp
  • Dùng Module
  • Dùng Package

Trong đó quy mô nhỏ nhất là hàm và lớn nhất là Package. Bạn có thể hình dung chúng ta viết hàm để chia nhỏ các công việc ra, sau đó gộp các hàm liên quan với nhau vào một lớp cụ thể, các lớp có liên quan với nhau lại được gộp vào một file làm một module, cứ thế chương trình lớn dần và chúng ta lại gộp các module thành một package. Chúng ta sẽ tìm hiểu về package ở bài sau.

Đặt tên module

Tên module là tên file có phần mở rộng là .py. Ví dụ như chúng ta có file empty.py thì empty là tên module. Mặc nhiên module này có một biến tên là __name__, biến này lưu trữ tên của module đang được sử dụng. Khi chúng ta viết một file Python rồi chạy thì biến thì tên module của file này được gọi là __main__.

Trong ví dụ dưới đây chúng ta có 2 file: empty.py và modulename.py. Khi chúng ta chạy từ file modulename.py thì file này được gọi là module main. Module main sử dụng module của file empty.py. Để sử dụng một module thì chúng ta dùng từ khóa import. 

"""
An empty module
"""

import empty
import sys

print (__name__)
print (empty.__name__)
print (sys.__name__)

Trong đoạn code trên chúng ta sử dụng 2 module, thứ nhất là module sys có sẵn trong Python và thứ hai là module empty do chúng ta tự tạo ra. Chúng ta in tên của các module này ra màn hình

__main__
empty
sys

Tên của module main sẽ luôn luôn là __main__. Các module khác sẽ là tên file.

Thư mục chứa module

Khi chúng ta import một module nào đó. Trình thông dịch sẽ tìm các module có sẵn trong Python. Nếu không thấy, nó sẽ tìm trong biến sys.path, biến này lưu trữ một list các chuỗi đường dẫn bao gồm đường dẫn đến thư mục hiện tại của file và đường dẫn đến thư mục cài đặt Python cùng với một số thư mục con bên trong. Nếu không tìm thấy module thì báo lỗi ImportError.


import sys
import textwrap

sp = sorted(sys.path)
dnames = ', '.join(sp)

print (textwrap.fill(dnames))

Đoạn code trên in ra tất cả các thư mục trong biến sys.path.

import textwrap

Module textwrap dùng để định dạng kiểu hiển thị.

sp = sorted(sys.path)

Dòng code trên lấy danh sách các đường dẫn thư mục và sắp xếp chúng.

dnames = ', '.join(sp)

Sau đó chúng ta nối chúng lại thành một chuỗi, ngăn cách bởi dấu phẩy.

C:\Users\PhoCode\, C:\Python, C:\Python\DLLs, C:\Python\lib,
C:\Python\lib\site-packages, C:\Python\python35.zip

Từ khóa import

Như chúng ta đã biết từ khóa này được dùng để tích hợp một module vào chương trình.

from module import *

Cú pháp trên có ý nghĩa là tích hợp tất cả những gì có trong module vào chương trình của chúng ta ngoại trừ các đối tượng có tên bắt đầu bằng dấu gạch dưới _. Những đối tượng này được sử dụng với tên của module chứ không thể được gọi riêng như những đối tượng khác.


from math import *

print (cos(3))
print (pi)

Đoạn code trên tích hợp tất cả các đối tượng có thể sử dụng trong module math vào chương trình. Chúng ta có thể gọi các hàm trong module này một cách trực tiếp chứ không cần phải thông qua tên module.

-0.9899924966
3.14159265359

Cách import kiểu này có thể làm rối loạn chương trình của chúng ta vì có thể có rất nhiều module trùng tên với nhau, do đó chúng sẽ bị ghi đè.


from math import  *

pi = 3.14

print (cos(3))
print (pi)

Đoạn code trên sẽ in ra con số 3.14. Vì trình thông dịch nghĩ rằng chúng ta muốn sử dụng biến pi do chúng ta tự gán chứ không phải biến pi có sẵn trong module math.

Ví dụ dưới đây kiểm nghiệm các hàm không được tích hợp vào chương trình bằng cách sử dụng kiểu import trên.

"""
names is a test module
"""

_version = 1.0

names = ["Paul", "Frank", "Jessica", "Thomas", "Katherine"]

def show_names():
   for i in names:
      print (i)

def _show_version():
   print (_version)
from names import *

print (locals())

show_names()

Biến _version và hàm _show_version() sẽ không được tích hợp vào module private vì tên của chúng có dấu gạch dưới ở đầu. Chúng ta dùng hàm locals() để in ra các module đã được tích hợp.

{'__builtins__': <module '__builtin__' (built-in)>, '__file__': './private.py', 
'show_names': <function show_names at 0xb7dd233c>, 
'names': ['Paul', 'Frank', 'Jessica', 'Thomas', 'Katherine'],
 '__name__': '__main__', '__doc__': None}
Paul
Frank
Jessica
Thomas
Katherine
from module import fun, var

Kiểu cú pháp trên chỉ tích hợp một số đối tượng được chỉ định vào module của chúng ta.

from math import sin, pi

print (sin(3))
print (pi)

Trong ví dụ trên chúng ta tích hợp 2 đối tượng sin và pi từ module math.


from names import _version, _show_version

print (_version)
_show_version()

Với kiểu cú pháp này chúng ta có thể tích hợp các module có tên có dấu gạch dưới ở đầu.

1.0
1.0
import module

Cú pháp cuối cùng này là cú pháp được sử dụng nhiều nhất. Bạn có thể dùng tất cả các đối tượng có trong module và để sử dụng thì bạn phải ghi tên module cùng với dấu chấm rồi mới đến tên đối tượng. Nhờ đó mà chương trình của bạn không bị rối tung lên.

import math

pi = 3.14

print (math.cos(3))
print (math.pi)
print (math.sin(3))
print (pi)

Trong ví dụ trên chúng ta import module math. Chúng ta có thể truy xuất được cả biến pi của chúng ta và biến pi trong module math.

-0.9899924966
3.14159265359
0.14112000806
3.14

import math as m

print (m.pi)
print (m.cos(3))

Ngoài ra khi import một module nào đó, bạn có thể muốn dùng một cái tên khác ngắn gọn hơn bằng cách thêm từ khóa as cùng với tên mà bạn muốn dùng. Tên này chỉ có hiệu lực trong file mà bạn đang viết.

3.14159265359
-0.9899924966

Nếu bạn import sai tên module thì lỗi ImportError sẽ nảy sinh.


try:
    import empty2
except ImportError, e:
    print ('Failed to import:', e)

Trong ví dụ trên, chúng ta không có module nào tên là empty2 do đó trình thông dịch báo lỗi.

Failed to import: No module named empty2

Thực thi module

Để sử dụng module thì chúng ta import nó từ chương trình của chúng ta nhưng chúng ta cũng có thể chạy chính nó. Ngoài các module có sẵn trong Python còn có rất nhiều lập trình viên viết các module khác cho Python. Thường thì sau khi viết xong họ hay viết những đoạn code để kiểm tra module của mình ở cuối file.

Chúng ta sẽ kiểm chứng điều này bằng cách viết module in dãy số fibonacci. Dãy số fibbonacci là dãy số mà số thứ i bằng tổng của số thứ i-1i-2, ngoại trừ hai số đầu tiên có giá trị là 1.


"""
A module containing the fibonacci
function. 
"""

def fib(n):
    a, b = 0, 1
    while b < n:
        print (b,)
        (a, b) = (b, a + b)


# testing

if __name__ == '__main__':
   fib(500)

Chúng ta sẽ chạy module này từ command prompt.

1 1 2 3 5 8 13 21 34 55 89 144 233 377

Trong đoạn code trên chúng ta có câu lệnh if để kiểm tra, nếu module được chạy từ trình biên dịch thì nó sẽ tự thực thi câu lệnh fib(500). Còn nếu được import từ module khác thì không.

>>> import fibonacci as fib
>>> fib.fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377

Python – Hướng đối tượng trong Python

Trong phần này chúng ta sẽ tìm hiểu về lập trình hướng đối tượng trong Python.

Lập trình hướng đối tượng (gọi tắt là OOP, từ chữ Anh ngữ object-oriented programming), là kĩ thuật lập trình hỗ trợ công nghệ đối tượng. OOP được xem là giúp tăng năng suất, đơn giản hóa độ phức tạp khi bảo trì cũng như mở rộng phần mềm bằng cách cho phép lập trình viên tập trung vào các đối tượng phần mềm ở bậc cao hơn. Ngoài ra, nhiều người còn cho rằng OOP dễ tiếp thu hơn cho những người mới học về lập trình hơn là các phương pháp trước đó (theo Wikipedia).

Trong OOP có các khái niệm cơ bản sau đây:

  • Trừu tượng (Abstraction)
  • Đa hình (Polymorphism)
  • Đóng gói (Encapsulation)
  • Kế thừa (Inheritance)

Các khái niệm trên giải thích theo wikipedia hay lấy trong sách rất khó hiểu nên mình sẽ làm ví dụ luôn và tới đoạn nào mình sẽ giải thích đoạn đó cho dễ hiểu.

Khái niệm đối tượng

Đối tượng là các thực thể của một lớp nào đó. Lớp là khuôn mẫu của các đối tượng. Ví dụ như list, tuple, dictionary, string, int… là các lớp. Khi chúng ta khai báo biến thuộc các lớp này thì chúng là các đối tượng. Tất cả mọi thứ trong Python đều là đối tượng.


import sys


def function(): pass


print (type(1))
print (type(""))
print (type([]))
print (type({}))
print (type(()))
print (type(object))
print (type(function))
print (type(sys))

Trong ví dụ trên nhờ vào hàm type() mà chúng ta biết được thực chất tất cả các kiểu dữ liệu và các module mà chúng ta đã học thực chất đều là các đối tượng.

<class 'int'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'tuple'>
<class 'type'>
<class 'function'>
<class 'module'>

Từ khóa class

Trong ví dụ trên, các lớp mà chúng ta kiểm tra bằng hàm type là các lớp có sẵn trong Python. Khi chúng ta muốn định nghĩa một lớp cho riêng mình thì chúng ta dùng từ khóa class. Một lớp có thể hiểu là một bản thiết kế để tạo ra một thực thể (mà chúng ta gọi là đối tượng). Một đối tượng là một thực thể được xây dựng từ một bản thiết kế đó (mà chúng ta gọi là lớp). Ví dụ chúng ta định nghĩa lớp Dog, thì chúng ta có các đối tượng là Huck, Lulu…. 😀

class First:
   pass

fr = First()

print (type(fr))
print (type(First))

Trong đoạn code trên chúng ta định nghĩa một lớp. Phần thân lớp tạm thời được để trống.

fr = First()

Ở dòng trên chúng ta xây dựng nên thực thể fr từ bản thiết kế First. Hay nói cách khác là chúng ta đã tạo ra đối tượng fr từ lớp First.

<class '__main__.First'>
<class 'type'>

Bên trong một lớp, chúng ta có thể định nghĩa các biến và hàm, biến và hàm bên trong một lớp được gọi là thuộc tínhphương thức. Chẳng hạn chúng ta định nghĩa lớp Employee (nhân viên), bên trong lớp này sẽ có thuộc tính Salary (lương) và phương thức calculateSalary (tính tiền lương).

Thuộc tính

Thuộc tính là biến nằm trong một lớp. Thuộc tính mô tả các đặc tính của một đối tượng. Trong Python có một phương thức đặc biệt gọi là  __init__() dùng để khởi tạo giá trị cho các thuộc tính của một đối tượng.

class Cat:
   def __init__(self, name):
      self.name = name


missy = Cat('Missy')
lucky = Cat('Lucky')

print (missy.name)
print (lucky.name)

Trong đoạn code trên, chúng ta định nghĩa lớp Cat. Bên trong lớp này, chúng ta định nghĩa phương thức __init__(). Phương thức __init__() là phương thức khởi tạo của tất cả các lớp, mỗi khi tạo một đối tượng phương thức này sẽ tự động được gọi.

def __init__(self, name):

Bất cứ phương thức nào của Python cũng đều phải có tham số đầu tiên là self rồi mới đến các tham số khác. self thực ra chỉ là biến đối tượng đã gọi phương thức này mà thôi. Chẳng hạn trong ví dụ trên khi chúng ta gọi missy = Cat("Missy") thì self chính là missy. 

self.name = name

Ở dòng trên chúng ta khởi tạo thuộc tính name và gán giá trị cho nó.

missy = Cat('Missy')
lucky = Cat('Lucky')

Trong hai dòng trên chúng ta dùng hàm Cat() để tạo ra hai đối tượng lớp thuộc lớp Cat. Chúng ta không trực tiếp đưa tham số self vào mà chỉ đưa các tham số thứ 2 trở đi thôi, self được tự động đưa vào bởi trình thông dịch. Trong ví dụ trên “Missy” và “Lucky” sẽ được gán cho thuộc tính name trong lớp Cat.

print (missy.name)
print (lucky.name)

Trong hai dòng code trên chúng ta in ra giá trị của thuộc tính name trong hai đối tượng Cat. Để truy xuất đến thuộc tính của một đối tượng thì chúng ta ghi tên đối tượng, dấu chấm và tên thuộc tính.

Missy
Lucky

Ngoài ra bạn có thể gán giá trị cho các thuộc tính ở bất cứ đâu sau phần định nghĩa lớp chứ không chỉ riêng bên trong phương thức khởi tạo.

class Dynamic:
   pass


d = Dynamic()
d.name = "Dynamic"
print (d.name)

Trong ví dụ trên chúng ta định nghĩa lớp Dynamic.

d.name = "Dynamic"

Ở dòng này chúng ta khai báo và gán giá trị cho thuộc tính name.

Dynamic

Một đặc điểm nữa trong Python bạn có thể định nghĩa các thuộc tính chung cho mọi đối tượng.


class Cat:
   species = 'mammal'

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


missy = Cat('Missy', 3)
lucky = Cat('Lucky', 5)

print (missy.name, missy.age)
print (lucky.name, lucky.age)

print (Cat.species)
print (missy.__class__.species)
print (lucky.species)

Trong ví dụ trên, chúng ta tạo ra hai đối tượng Cat với thuộc tính name và age, hai thuộc tính này được khai báo bên trong phương thức __init__() và được gọi là thuộc tính đối tượng. Ngoài ra hai đối tượng này còn có một thuộc tính chung là thuộc tính species, thuộc tính này được khai báo ở ngoài phương thức __init__()  được gọi là thuộc tính lớp. Thuộc tính lớp được chia sẻ chung cho mọi đối tượng của lớp đó, trong khi thuộc tính đối tượng chỉ dành riêng cho đối tượng. Nghĩa là khi bạn thay đổi giá trị của thuộc tính chia sẻ trong một đối tượng thì tất cả các thuộc tính chia sẻ đó trong các đối tượng khác cũng thay đổi theo.

print (Cat.species)
print (missy.__class__.species)

Có hai cách để truy xuất thuộc tính lớp, thứ nhất là thông qua tên lớp, cách thứ hai là thông qua một thuộc tính đặc biệt nữa là thuộc tính __class__.

Missy 3
Lucky 5
mammal
mammal
mammal

Phương thức

Phương thức chẳng qua là các hàm, chỉ khác hàm bình thường ở chỗ chúng được định nghĩa bên trong một lớp. Các phương thức được sử dụng để thực hiện các công việc cụ thể. Phương thức là một thành phần quan trọng trong khái niệm Encapsulation (đóng gói). Chẳng hạn như bạn có một lớp tên là Network, lớp này có phương thức connect() dùng để kết nối đến các máy tính trong mạng LAN, thì bạn chỉ quan tâm rằng phương thức này làm công việc kết nối mạng chứ không quan tâm đến việc nó kết nối như thế nào.

class Circle:
   pi = 3.141592

   def __init__(self, radius=1):
      self.radius = radius 

   def area(self):
      return self.radius * self.radius * Circle.pi

   def setRadius(self, radius):
      self.radius = radius

   def getRadius(self):
      return self.radius


c = Circle()

c.setRadius(5)
print (c.getRadius())
print (c.area())

Trong ví dụ trên, chúng ta định nghĩa lớp Circle (hình tròn) và 3 phương thức mới.

 def area(self):
    return self.radius * self.radius * Circle.pi

Phương thức area() trả về diện tích hình tròn.

def setRadius(self, radius):
   self.radius = radius

Phương thức setRadius() thiết lập giá trị cho thuộc tính radius (bán kính).

 def getRadius(self):
    return self.radius

Phương thức getRadius() trả về lấy giá trị bán kính.

 c.setRadius(5)

Chúng ta gọi các phương thức thông qua biến đối tượng.

5
78.5398

Kế thừa

Kế thừa là định nghĩa một lớp dựa trên một lớp đã được định nghĩa trước đó. Lớp kế thừa từ lớp khác được gọi là lớp dẫn xuất, lớp được các lớp khác kế thừa mình thì gọi là lớp cơ sở. Kế thừa trong lập trình hướng đối tượng cho phép chúng ta sử dụng lại mã nguồn và giảm độ phức tạp của chương trình. Lớp dẫn xuất có thể kế thừa hoặc mở rộng các tính năng của lớp cơ sở.

class Animal:
   def __init__(self):
      print ("Animal created")

   def whoAmI(self):
      print ("Animal")

   def eat(self):
      print ("Eating")


class Dog(Animal):
   def __init__(self):
      Animal.__init__(self)
      print ("Dog created")

   def whoAmI(self):
      print ("Dog")

   def bark(self):
      print ("Woof!")


d = Dog()
d.whoAmI()
d.eat()
d.bark()

Trong ví dụ trên chúng ta định nghĩa hai lớp là là Animal và lớp Dog. Lớp Dog kế thừa từ lớp Animal, thừa hưởng một số phương thức của lớp Animal và có các phương thức của riêng nó. Ở trên lớp Dog kế thừa phương thức eat(), kế thừa và thay đổi phương thức whoAmI(), ngoài ra lớp Dog còn có phương thức của riêng nó là phương thức bark().

class Dog(Animal):
    def __init__(self):
        Animal.__init__(self)
        print ("Dog created")

Để kế thừa một lớp thì chúng ta đặt tên lớp đó bên trong cặp dấu ngoặc tròn () ngay phía sau phần định nghĩa tên lớp. Nếu bên trong lớp cơ sở đã định nghĩa phương thức __init__(), chúng ta phải gọi lại phương thức __init__() từ lớp cơ sở.

Animal created
Dog created
Dog
Eating
Woof!

Đa hình

Đa hình là bạn có thể sử dụng các toán tử hay các hàm trên nhiều kiểu dữ liệu khác nhau.


a = "alfa"
b = (1, 2, 3, 4)
c = ['o', 'm', 'e', 'g', 'a']

print (a[2])
print (b[1])
print (c[3])

Bản thân các hàm có sẵn trong Python cũng có tính chất đa hình. Chẳng hạn như hàm print() mà chúng ta hay dùng, mỗi lần gọi hàm này bạn có thể đưa vào hầu hết các kiểu dữ liệu khác nhau.

f
2
g

Trong hướng đối tượng thì tính đa hình càng được phát huy tác dụng.

class Animal:
   def __init__(self, name=''):
      self.name = name

   def talk(self):
      pass


class Cat(Animal):
   def talk(self):
      print ("Meow!")


class Dog(Animal):
   def talk(self):
      print ("Woof!")


a = Animal()
a.talk()

c = Cat("Missy")
c.talk()

d = Dog("Rocky")
d.talk()

Trong ví dụ trên, chúng ta định nghĩa hai lớp chó (Dog) và mèo (Cat) kế thừa từ lớp Animal. Do đó cả hai lớp này đều kế thừa phương thức talk() của lớp Animal, nhưng mỗi lớp lại in ra hai dòng text khác nhau.

Meow!
Woof!

Các phương thức đặc biệt

Tất cả các lớp dù là có sẵn hay do chúng ta định nghĩa đều kế thừa từ một lớp gốc trong Python có tên là object. Lớp này có sẵn một số phương thức và đương nhiên là các lớp do chúng ta định nghĩa đều kế thừa các phương thức này, ví dụ như phương thức __init__()… Trong Python khi chúng ta gọi đến các hàm hay toán tử được xây dựng sẵn như print(), del… chúng sẽ gọi đến các phương thức gốc của lớp object. Chính vì các lớp do chúng ta định nghĩa đều được kế thừa từ lớp object nên chúng ta cũng có thể dùng các hàm hay toán tử có sẵn trong Python với các lớp của chúng ta. Trong các ngôn ngữ như C++ thì tính chất này được gọi là quá tải toán tử (operator overloading).

class Book:
   def __init__(self, title, author, pages):
      print ("A book is created")
      self.title = title
      self.author = author
      self.pages = pages

   def __str__(self):
      return "Title:%s , author:%s, pages:%s " % \
              (self.title, self.author, self.pages)

   def __len__(self):
      return self.pages

   def __del__(self):
      print ("A book is destroyed")


book = Book("Inside Steve's Brain", "Leander Kahney", 304)

print (book)
print (len(book))
del book

Trong ví dụ trên, chúng ta định nghĩa lớp Book. Bên trong lớp này chúng ta định nghĩa 4 phương thức được kế thừa từ lớp object là __init__(),__str__(), __len__() và __del__().

print (book)

Khi sử dụng hàm print(), hàm này sẽ gọi đến phương thức __str__(), do đó khi chúng ta kế thừa lại phương thức này, hàm print() sẽ gọi đến phương thức __str__() trong lớp Book của chúng ta.

print (len(book))

Tương tự, hàm len() gọi đến phương thức __len__()

del book

Từ khóa del gọi đến phương thức __del__() và trên thực tế là phương thức này làm công việc hủy bỏ một đối tượng ra khỏi bộ nhớ. Nhưng ở đây chúng ta kế thừa phương thức này chỉ làm công việc là in ra một đoạn text.

Trong ví dụ dưới đây, chúng ta sẽ kế thừa các toán tử cộng và trừ.


class Vector:

  def __init__(self, data):
    self.data = data

  def __str__(self):
    return repr(self.data)

  def __add__(self, other):
    data = []
    for j in range(len(self.data)):
      data.append(self.data[j] + other.data[j])
    return Vector(data)

  def __sub__(self, other):
    data = []
    for j in range(len(self.data)):
      data.append(self.data[j] - other.data[j])
    return Vector(data)


x = Vector([1, 2, 3])
y = Vector([3, 0, 2])
print (x + y)
print (y - x)
def __add__(self, other):
  data = []
  for j in range(len(self.data)):
    data.append(self.data[j] + other.data[j])
  return Vector(data)

Chúng ta định nghĩa lớp Vector, lớp vector này kế thừa hai phương thức __add__()__sub__(). phương thức __add__() sẽ được gọi khi sử dụng toán tử + và phương thức __sub__() sẽ được gọi khi sử dụng toán tử -.

[4, 2, 5]
[2, -2, -1]

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

Python – Từ khóa

Trong phần này chúng ta sẽ tìm hiểu về hệ thống từ khóa có trong Python.

Dưới đây là danh sách các từ khóa trong Python.

and       del       from      not       while
as        elif      global    or        with
assert    else      if        pass      yield
break     except    import    print
class     exec      in        raise
continue  finally   is        return 
def       for       lambda    try

Python luôn được cập nhật, danh sách các từ khóa trên có thể sẽ không giống với phiên bản bạn đang dùng


import sys
import keyword


print ("Python version: ", sys.version_info)
print ("Python keywords: ", keyword.kwlist)

Đoạn code trên sẽ in ra phiên bản Python và danh sách các từ khóa của nó.

Các từ khóa điều khiển luồng chương trình

Từ khóa while là từ khóa cơ bản để điều khiển luồng chương trình. Các câu lệnh bên trong vòng lặp while sẽ được thực thi cho đến khi điều kiện sai.


numbers = [22, 34, 12, 32, 4]
sum = 0

i = len(numbers)

while (i != 0):
   i -= 1
   sum = sum + numbers[i]

print ("The sum is: ", sum)

Đoạn code trên tính tổng của các số có trong một list. Đầu tiên chúng ta tính số lượng phần tử của list và gán vào biến i, sau đó cứ mỗi vòng lặp, chúng ta lấy phần tử thứ của list để tính tổng rồi trừ đi 1. Vòng lặp dừng lại khi = 0.

Ngoài ra chúng ta có thể dùng từ khóa break để dừng vòng lặp ngay nếu muốn.


import random

while (True):
   val = random.randint(1, 30)
   print (val,)
   if (val ==  22):
      break

Trong đoạn code trên, chúng ta cho một vòng lặp chạy, cứ mỗi lần lặp, chúng ta lấy ngẫu nhiên một số từ 1 đến 30, nếu số ngẫu nhiên là 22 thì chúng ta ngắt vòng lặp bằng từ khóa break.

14 14 30 16 16 20 23 15 17 22

Trong ví dụ tiếp theo, chúng ta sẽ sử dụng từ khóa continue. Từ khóa này có tác dụng bỏ qua lần lặp đang thực hiện dở để thực hiện lần lặp tiếp theo.


import random

num = 0

while (num < 1000):
   num = num + 1
   if (num % 2) == 0:
      continue
   print (num,)

Trong đoạn code trên, chúng ta in ra các chữ số bé hơn 1000 mà không thể chia hết cho 2.

Ví dụ tiếp theo sử dụng từ khóa if, đây là từ khóa được dùng rất nhiều trong luồng điều khiển của chương trình.


# licence.py

age = 17

if age > 18:
   print ("Driving licence issued")
else:
   print ("Driving licence not permitted")

Trong đoạn code trên, chúng ta kiểm tra xem biến age bé hơn hay lớn hơn 18 để in ra các chuỗi khác nhau.

Đi cùng với từ khóa if và từ khóa elif, từ khóa này tương đương với else if trong các ngôn ngữ khác.


name = "Luke"

if name == "Jack":
   print ("Hello Jack!")
elif name == "John":
   print ("Hello John!")
elif name == "Luke":
   print ("Hello Luke!")
else:
   print ("Hello there!")

Trong đoạn code trên, các câu lệnh if sẽ tuần tự được thực hiện cho đến khi có điều kiện đúng. Nếu không có điều kiện nào thỏa thì câu lệnh sau từ khóa else sẽ được thực hiện.

Hello Luke!

Từ khóa for được dùng để duyệt qua một danh sách các đối tượng nào đó.


lyrics = """\
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 
"""


for i in lyrics:
   print (i,)

Trong ví dụ trên, chúng ta có một chuỗi là lời bài hát. Chúng ta duyệt qua chuỗi đó, mỗi lần duyệt chúng ta in các chữ cái có trong chuỗi ra, dấu phẩy trong hàm print có tác dụng ngăn không cho xuống dòng.

A r e   y o u   r e a l l y   h e r e   o r   a m   I   d r e a m i n g 
I   c a n ' t   t e l l   d r e a m s   f r o m   t r u t h   
f o r   i t ' s   b e e n   s o   l o n g   s i n c e   I   h a v e   s e e n   y o u 
I   c a n   h a r d l y   r e m e m b e r   y o u r   f a c e   a n y m o r e   

Biểu thức boolean

Ở đây mình giới thiệu lại các từ khóa boolean đã được học trong bài trước là: is, or, and, và not.

print (None == None)
print (None is None)

print (True is True)

print ([] == [])
print ([] is [])

print ("Python" is "Python")

Toán tử == kiểm tra xem 2 đối tượng có cùng giá trị hay không. Từ khóa is kiểm tra xem 2 đối tượng có cùng bộ nhớ hay không vì trong lập trình một địa chỉ bộ nhớ có thể được tham chiếu bởi nhiều đối tượng.

True
True
True
True
False
True

Đoạn tiếp theo có thể sẽ hơi khó hiểu nhưng bạn cũng không cần đọc làm gì 😀

Sự khác nhau giữa toán tử == và từ khóa is là khi chúng được sử dụng trên các đối tượng thì toán tử == sẽ so sánh các giá trị trong khi từ khóa is sẽ so sánh địa chỉ của chúng trong bộ nhớ. Do đó trong biểu thức []==[] kết quả trả về True vì chúng đều là các list rỗng, nhưng []is[] lại cho kết quả False vì chúng là các thực thể khác nhau trong bộ nhớ. Còn đối với các đối tượng None, True thì lại khác, đây là các đối tượng đặc biệt, trong Python chúng là duy nhất, không hề có 2 đối tượng None hay True nên kết quả trả về True. Đối với trường hợp so sánh 2 string("Python" is "Python") thì do Python tự động tối ưu bộ nhớ nên những string có giá trị giống nhau sẽ được sử dụng chung bộ nhớ, kết quả trả về True.

Tiếp theo là từ khóa not, từ khóa này đảo ngược một giá trị boolean.


grades = ["A", "B", "C", "D", "E", "F"]

grade = "L"

if grade not in grades:
   print ("unknown grade")

Trong ví dụ trên, chúng ta kiểm tra xem giá trị của biến grade không thuộc list grades hay không. Từ khóa in có tác dụng kiểm tra xem một giá trị có thuộc một danh sách hay không, khi ta thêm từ khóa not vào trước thì giá trị của in bị đảo ngược.

unknown grade

Từ khóa and trả về giá trị True khi cả hai biểu thức là True.

sex = "M"
age = 26

if age < 55 and sex == "M":
   print ("a young male")

Trong ví dụ trên, nếu biến age bé hơn 55 biến sex là “M” thì in dòng chữ “a young male” ra màn hình.

a young male

Khác với từ khóa and, từ khóa or chỉ cần một biểu thức là True thì trả về True.


name = "Jack"

if ( name == "Robert" or name == "Frank" or name == "Jack" 
      or name == "George" or name == "Luke"):
   print ("This is a male")

Hai toán tử andor chỉ xét tới toán hạng thứ hai khi toán hạng thứ nhất thỏa điều kiện. Ví dụ trong toán tử and nếu toán hạng đầu tiên là false thì tự động kết quả trả về sẽ là false chứ không xét toán hạng thứ 2 nữa, còn đối với toán tử or thì nếu toán hạng đầu tiên là True thì lập tức kết quả trả về là True luôn chứ cũng không xét toán hạng thứ hai nữa.

Ví dụ.


x = 10
y = 0

if (y != 0 and x/y < 100):
   print ("a small value")

Đoạn code trên sẽ trả về False vì y khác 10 và toán hạng thứ hai không được xét đến. Nếu không sẽ xảy ra lỗi exception vì chúng ta không thể chia một số cho 0.

Module

Các từ khóa dưới đây làm việc với module. Một module thực chất là một file chứa code Python trong đó để có thể sử dụng bất cứ lúc nào.

Đầu tiên là từ khóa import, từ khóa này được sử dụng để tích hợp module cần sử dụng vào chương trình.


import math

print (math.pi)

Trong ví dụ trên, chúng ta sử dụng từ khóa import để tích hợp module math vào chương trình của chúng ta. Sau đó chúng ta in ra hằng số pi của module này.

Từ khóa as được dùng để đổi tên module mà chúng ta muốn sử dụng thành tên mà chúng ta thích.


import random as rnd

for i in range(10):
   print (rnd.randint(1, 10),) 

Trong ví dụ trên, chúng ta import module random. Chúng ta sử dụng hàm randint() để lấy giá trị ngẫu nhiên từ 1 đến 10. Nhưng chúng ta không sử dụng cái tên random mà sử dụng tên rnd do chúng ta đặt. Tuy nhiên khi sử dụng tên mới bạn không được đổi tên file mã nguồn của bạn thành random.py hoặc rnd.py, nếu không sẽ báo lỗi.

1 2 5 10 10 8 2 9 7 2

Trong một module có rất nhiều hàm, biến, lớp… khi dùng từ khóa import mặc nhiên chúng ta được sử dụng toàn bộ mọi thứ có trong module. Nhưng nếu bạn chỉ muốn dùng một vài thứ nhất định trong module đó thì sử dụng từ khóa from.


from sys import version

print (version)

Câu lệnh from sys import version có nghĩa là chỉ sử dụng biến version trong module sys. Và khi in ra màn hình thì chúng ta không cần đưa tên module ra trước. Lúc này biến version có đặc tính y hệt như những biến thông thường.

3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)]

Hàm

Tiếp theo chúng ta sẽ tìm hiểu các từ khóa làm việc với hàm. Từ khóa def là từ khóa bắt đầu định nghĩa hàm. Chúng ta sẽ tìm hiểu sâu hơn về hàm ở bài sau.

def root(x):
   return x * x

a = root(2)
b = root(15)

print (a, b)

Trong ví dụ trên chúng ta viết một hàm đơn giản. Hàm này tính bình phương của một số cho trước. Từ khóa return trả về giá trị của hàm và thoát hàm.

Từ khóa lambda có tác dụng tạo một hàm ẩn, hàm ẩn là hàm không dính tới một cái tên cụ thể nào. Trong các ngôn ngữ khác thì hàm này được gọi là hàm nội tuyến (inline function).


for i in (1, 2, 3, 4, 5):
   a =  lambda x: x * x
   print (a(i),)

Trong ví dụ trên, chúng ta không định nghĩa một hàm với từ khóa def mà dùng hàm ẩn.

1 4 9 16 25

Khi định nghĩa một hàm thì các biến trong hàm đó chỉ tồn tại bên trong hàm, khi kết thúc hàm chúng bị xóa khỏi bộ nhớ. Tuy nhiên nếu muốn sử dụng chúng ngoài thân hàm thi chúng ta có thể sử dụng từ khóa global.


x = 15

def function():
   global x
   x = 45

function()
print (x)
45

Exception

Tiếp theo chúng ta tìm hiểu về các từ khóa làm việc với exception. Chi tiết về exception sẽ được đề cập ở các bài sau.

Fargo
Aguirre, der Zorn Gottes
Capote
Grizzly man
Notes on a scandal

Ở trên là một file text chứa các tựa phim. Chúng ta sẽ đọc file này.


f = None

try:
   f = open('films', 'r')
   for i in f:
      print (i,)
except IOError:
   print ("Error reading file")

finally:
   if f:
       f.close()

Trong ví dụ trên, chúng ta đọc một file. Nếu không có lỗi xảy ra thì nội dung file sẽ được in ra màn hình. Nhưng đôi khi có những lỗi xảy ra trong quá trình đọc, chẳng hạn như tên file không chính xác, lúc này sẽ xuất hiện lỗi exception IOError. Từ khóa except có tác dụng “bắt” lỗi này và xử lý nó. Từ khóa finally có tác dụng thực thi các câu lệnh cho dù có lỗi hay không có lỗi xảy ra.

Trong ví dụ tiếp theo, chúng ta sẽ tìm hiểu về từ khóa raise.


class YesNoException(Exception):
   def __init__(self):
      print ('Invalid value')


answer = 'y'

if (answer != 'yes' and answer != 'no'):
   raise YesNoException
else:
   print ('Correct value')

Trong Python có rất nhiều các exception được định nghĩa sẵn, nhưng tất nhiên sẽ có trường hợp chúng ta cần các exception riêng cho chúng ta tự định nghĩa. Từ khóa raise có tác dụng “phát” exception khi cần.

Invalid value
Traceback (most recent call last):
  File "./userexception.py", line 13, in <module>
    raise YesNoException
__main__.YesNoException

Một số từ khóa khác

Từ khóa del có tác dụng xóa một đối tượng.

a = [1, 2, 3, 4]

print (a)
del a[:2]
print (a)

Trong ví dụ trên, chúng ta có một list các số nguyên. Sau đó chúng ta xóa phần tử đầu tiên trong list.

[1, 2, 3, 4]
[3, 4]

Từ khóa pass có tác dụng… không làm gì cả :D.

 def function():
     pass

Đôi khi chúng ta định nghĩa một hàm nhưng chưa muốn viết phần thân hàm mà để sau. Nhưng chúng ta không thể để thân hàm trống không được. Lúc đó chúng ta để từ khóa pass trong thân hàm.

Từ khóa assert được dùng trong quá trình debug. Thường chúng ta dùng từ khóa này để kiểm tra các trạng thái của đối tượng. Ví dụ chúng ta có một chương trình tính lương, vì lương không thể bé hơn 0 nên nếu chúng ta có thể dùng từ khóa assert để kiểm tra xem lương có lớn hơn 0 hay không. Nếu sai thì trình thông dịch sẽ báo lỗi.


salary = 3500
salary -= 3560 # a mistake was done

assert salary > 0

Đoạn code trên Ví dụ về chương trình tính lương.

Traceback (most recent call last):
  File "./salary.py", line 9, in <module>
    assert salary > 0
AssertionError

Lỗi exception AssertionError sẽ xảy ra.

Cuối cùng là từ khóa class, từ khóa class là một trong những từ khóa quan trọng nhất trong lập trình hướng đối tượng. Từ khóa này dùng để tạo những kiểu dữ liệu do người dùng định nghĩa. Chúng ta sẽ tìm hiểu về lập trình hướng đối tượng (Object Oriented Programming – OOP) trong các bài sau.

class Square:
   def __init__(self, x):
      self.a = x

   def area(self):
      print (self.a * self.a)


sq = Square(12)
sq.area()

Trong đoạn code trên. Chúng ta tạo ra lớp Square (hình vuông), bên trong lớp này chúng ta định nghĩa phương thức khởi tạo và phương thức tính diện tích hình vuông.

Python – Toán tử

Trong phần này chúng ta sẽ tìm hiểu về các toán tử có trong Python.

Toán tử ở đây là các kí tự dùng để thực thi các phép tính nào đó. Hầu hết các toán tử trong lập trình đều bắt nguồn từ các phép toán trong toán học. Chỉ khác là trong lập trình thì toán tử thao tác với dữ liệu.

Trong Python, toán tử được chia ra làm những loại sau:

  • Toán tử số học
  • Toán tử boolean
  • Toán tử quan hệ
  • Toán tử thao tác bit

Trong một biểu thức toán tử có thể có một hoặc hai toán hạng. Toán hạng là các giá trị hay các biến tham gia vào biểu thức. Toán tử sẽ xử lý các toán hạng và trả về kết quả. Ví dụ a = 1 + c, trong đó dấu = và dấu + là các toán tử, còn a, 1c là các toán hạng.

Dấu + và – trong toán tử cộng trừ có thể được dùng để làm dấu của số. Nhưng thường thì chúng ta chỉ dùng dấu – để biểu diễn số nguyên âm chứ ít ai dùng dấu + để biểu diễn số nguyên dương.

>>> a = 1
>>> -a
-1
>>> -(-a)
1

Toán tử gán

Toán tử gán có kí hiệu là dấu =, ý nghĩa của toán tử này là gán một giá trị cho một biến nào đó. Toán hạng nằm bên trái dấu = sẽ được gán giá trị.

>>> x = 1
>>> x
1

Trong đoạn code trên chúng ta gán x bằng 1.

>>> x = x + 1
>>> x
2

Trong đoạn code kế tiếp thì biểu thức x = x + 1 không có ý nghĩa trong toán học. Nhưng trong lập trình thì hợp lệ. Biểu thức đó có ý nghĩa tăng giá trị của x lên 1. Ở bên phải toán tử, biểu thức x + 1 có giá trị là 2 sẽ được gán cho biến x.

>>> a = b = c = 4
>>> print (a, b, c)
4 4 4

Trong Python và hầu hết các ngôn ngữ lập trình, chúng ta có thể gán 1 giá trị cho nhiều biến cùng một lúc.

>>> 3 = y
  File "<stdin>", line 1
SyntaxError: can't assign to literal

Đoạn code trên báo lỗi vì bạn chỉ có thể gán giá trị hoặc biến cho một biến chứ không thể gán cho một giá trị khác.

Toán tử số học

Bảng dưới đây mô tả các toán tử số học trong Python.

Kí HIỆU TÊN
+ Cộng
- Trừ
* Nhân
/ Chia
// Floor division
% Chia lấy phần dư
** Lũy thừa

Đoạn code dưới đây ví dụ về các toán tử trên.

a = 10
b = 11
c = 12

add = a + b + c
sub = c - a
mult = a * b
div = c / 3

pow = a ** 2

print (add, sub, mult, div)
print (pow)

Tất cả các toán tử này đều có trong toán học.

33 2 110 4.0
100

Kết quả trả về.

print (9 / 3)
print (9 / 4)
print (9 / 4.0)
print (9 // 4.0)
print (9 % 4)

Đoạn code trên ví dụ rõ hơn về phép toán chia.

print (9 // 4.0)

Dòng trên ví dụ về toán tử //, đây là toán tử làm tròn xuống, ví dụ 2.25 hay 2.75 đều được làm tròn về 2.0.

print (9 % 4)

Toán tử % là phép toán lấy phần dư. Ví dụ 9 chia 4 được 2 1.

3.0
2.25
2.25
2.0
1
>>> 'return' + 'of' + 'the' + 'king'
'returnoftheking'

Trong các bài trước, chúng ta đã biết là toán tử cộng có thể được dùng để nối string.

>>> 3 + ' apples'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Chúng ta không thể cộng một số với một string. Kết quả sẽ cho ra một lỗi exception.

>>> str(3) + ' apples'
'3 apples'

Nếu muốn chuyển một số sang chuỗi để nối vào một chuỗi thì chúng ta phải dùng hàm str() để chuyển.

Tuy nhiên toán tử * lại có thể dùng cho chuỗi và số.

>>> 'dollar ' * 5
'dollar dollar dollar dollar dollar '

Toán tử boolean

Trong Python, chúng ta có các toán tử and, or và not. Các toán tử này làm công việc mang tính logic. Chúng thường được dùng trong các câu lệnh if và while.


# andop.py

print (True and True)
print (True and False)
print (False and True)
print (False and False)

Đoạn code trên ví dụ về các toán tử and. Kết quả chỉ trả về True khi cả hai đều là True.

True
False
False
False

Đoạn code dưới đây ví dụ về toán tử or. Kết quả trả về True khi một trong hai toán hạng là True.

print (True or True)
print (True or False)
print (False or True)
print (False or False)
True
True
True
False

Toán tử not chỉ làm việc với một toán hạng. Toán tử này sẽ đảo ngược giá trị từ True thành False và ngược lại.

print (not False)
print (not True)
print (not ( 4 < 3 ))
True
False
True

Hai toán tử andor chỉ xét tới toán hạng thứ hai khi toán hạng thứ nhất thỏa điều kiện. Ví dụ trong toán tử and nếu toán hạng đầu tiên là false thì tự động kết quả trả về sẽ là false chứ không xét toán hạng thứ 2 nữa, còn đối với toán tử or thì nếu toán hạng đầu tiên là True thì lập tức kết quả trả về là True luôn chứ cũng không xét toán hạng thứ hai nữa.

Ví dụ.

x = 10
y = 0

if (y != 0 and x/y < 100):
      print ("a small value")

Đoạn code trên sẽ trả về False vì y khác 10 và toán hạng thứ hai không được xét đến. Nếu không sẽ xảy ra lỗi exception vì chúng ta không thể chia một số cho 0.

Toán tử quan hệ

Các toán tử quan hệ dùng để so sánh các giá trị, kết quả trả về là True hoặc False.

KÍ HIỆU Ý NGHĨA
< Bé hơn
<= Bé hơn hoặc bằng
> Lớn hơn
>= Lớn hơn hoặc bằng
== Bằng
!= or <> Không bằng (khác)
is định danh đối tượng
is not định danh không phải đối tượng

Bảng trên mô tả các toán tử quan hệ.

>>> 3 < 4 True >>> 4 == 3
False
>>> 4 >= 3
True

Chúng ta không chỉ có thể dùng các toán tử quan hệ với các số mà có thể dùng với các đối tượng khác nữa, mặc dù làm thế cũng không ý nghĩa mấy.

>>> "six" == "six"
True
>>> "a" > 6
True
>>> 'a' < 'b'
True

Chúng ta có thể so sánh hai string, hai kí tự hoặc so sánh một string với một số.

>>> 'a' < 'b'

Trong máy tính thì các kí tự này đều mang một mã số bên mình, khi so sánh hai kí tự thì thực chất máy tính so sánh hai mã số này. Mã số của các kí tự này được lưu trong các bảng mã. Mặc định là bảng mã ASCII.

print ('a' < 'b')

print ("a is:", ord('a'))
print ("b is:", ord('b'))

Nếu như bạn muốn biết mã số của các kí tự thì bạn có thể dùng hàm ord().

True
a is: 97
b is: 98

Như vậy trong máy tính khi so sánh hai kí tự ‘a’ và ‘b’ thực chất là so sánh hai số 97 và 98.

>>> "ab" > "aa"
True

Khi so sánh một chuỗi, các kí tự đầu tiên sẽ được so sánh với nhau, nếu chúng bằng nhau, các kí tự thứ 2, thứ 3…. sẽ lần lượt được so sánh. Thực ra chúng ta cũng ít khi so sánh hai chuỗi vì việc này cũng không có ý nghĩa mấy.

print (None == None)
print (None is None)

print (True is True)

print ([] == [])
print ([] is [])

print ("Python" is "Python")

Toán tử == có tác dụng kiểm tra xem hai toán hạng có bằng nhau hay không. Từ khóa is kiểm tra xem toán hạng có phải là một đối tượng kiểu nào đó hay không.

True
True
True
True
False
True

Đoạn tiếp theo có thể sẽ hơi khó hiểu nhưng bạn cũng không cần đọc làm gì 😀

Sự khác nhau giữa toán tử == và từ khóa is là khi chúng được sử dụng trên các đối tượng thì toán tử == sẽ so sánh các giá trị trong khi từ khóa is sẽ so sánh địa chỉ của chúng trong bộ nhớ. Do đó trong biểu thức []==[] kết quả trả về True vì chúng đều là các list rỗng, nhưng []is[] lại cho kết quả False vì chúng là các thực thể khác nhau trong bộ nhớ. Còn đối với các đối tượng None, True thì lại khác, đây là các đối tượng đặc biệt, trong Python chúng là duy nhất, không hề có 2 đối tượng None hay True nên kết quả trả về True. Đối với trường hợp so sánh 2 string ("Python" is "Python") thì do Python tự động tối ưu bộ nhớ nên những string có giá trị giống nhau sẽ được sử dụng chung bộ nhớ, kết quả trả về True.

Toán tử thao tác bit

Đối với loài người chúng ta thì chúng ta sử dụng bộ chữ số hệ thâp phân (tức hệ 10) gồm các chữ số từ 0 đến 9, bộ chữ số này rất tiện cho chúng ta vì mặc nhiên chúng ta có 10 ngón tay và 10 ngón chân. Đối với máy tính thì khác, máy tính chỉ dùng một bộ chữ số đơn giản là hệ nhị phân, chỉ gồm hai chữ số 0 và 1. Các toán tử thao tác bit là các phép toán thực hiện với chữ số nhị phân. Tuy nhiên trong các ngôn ngữ cấp cao như Python chúng ta cũng ít khi dùng đến chúng.

KÍ HIỆU Ý NGHĨA
~ Phép nghịch đảo
^ Phép xor
& Phép and
| Phép or
<< Phép dịch trái
>> Phép dịch phải

Phép nghịch đảo có tác dụng đổi các bit từ 0 sang 1 và ngược lại.

>>> ~7
-8
>>> ~-8
7

Phép nghịch đảo của số 7 là -8. Nếu chúng ta thực hiện nghịch đảo của -8 sẽ lại được 7.

Toán tử and so sánh 2 bit với nhau, kết quả là 1 nếu cả hai là 1, ngược lại thì ra 0.

     00110
  &  00011
   = 00010
>>> 6 & 3
2
>>> 3 & 6
2

Toán tử or so sánh 2 bit với nhau. Nếu một trong hai bit là 1 thì kết quả sẽ ra 1. Nếu cả 2 là 0 thì kết quả ra 0.

     00110
  |  00011
   = 00111

Kết quả của phép toán trên là 00110 hay số 7 trong hệ 10.

>>> 6 | 3
7

Phép toán xor so sánh 2 bit. Nếu cả 2 giống nhau thì ra 0, ngược lại thì ra 1.

     00110
  ^  00011
   = 00101

Kết quả trên ra 00101 hoặc 5 trong hệ 10.

>>> 6 ^ 3
5

TIếp theo là các toán tử dịch bit. Chúng ta có phép dịch bit sang trái và sang phải. Ví dụ với dãy bit 00110 khi dịch sang trái sẽ được 01100, còn dịch sang phải sẽ được 00011. Phép dịch bit sang trái còn mang ý nghĩa là nhân một số cho 2, còn dịch sang phải mang ý nghĩa chia một số cho 2.

     00110
  >>  00001
   = 00011

Trong ví dụ trên, chúng ta có 00110 là số 6 trong hệ 10, khi dịch dang phải 1 bit, chúng ta được dãy bit 00011 hay 3 trong hệ 10. Tức là chúng ta đã chia 6 cho 2 và được 3.

>>> 6 >> 1
3
     00110
  << 00001
   = 01100

Ngược lại cũng với dãy bit 00110 khi dịch trái chúng ta được 01100 tức 12 trong hệ 10. Tức là chúng ta đã nhân 6 cho 2 và được 12.

>>> 6 << 1
12

Toán tử gán bằng

Các toán tử gán bằng bao gồm 2 kí tự, thực chất chúng chỉ là cách viết tắt thôi.

>>> i = 1
>>> i = i + 1
>>> i
2
>>> i += 1
>>> i
3

Toán tử += là một toán tử gán bằng. Ví dụ i += 1 tương đương với i = i + 1. Cách viết này rất được hay dùng.

Dưới đây là một số toán tử gán bằng khác:

-=   *=   /=   //=   %=   **=   &=   |=   ^=   >>=   <<=

Mức độ ưu tiên của toán tử

Khi một biểu thức có nhiều toán tử, chúng sẽ được thực hiện từ các toán tử có độ ưu tiên cao hơn đến thấp hơn.

Ví dụ với biểu thức dưới đây, phép toán * sẽ được thực hiện trước rồi mới đến phép toán +.

3 + 5 * 5

Cũng giống như trong toán, chúng ta có thể tăng mức độ ưu tiên cho một toán tử bằng cặp dấu ().

(3 + 5) * 5

Các toán tử nằm trong cặp dấu () sẽ được ưu tiên thực hiện trước.

Dưới đây là danh sách các toán tử được sắp xếp theo mức độ ưu tiên từ cao xuống thấp.

   unary +  -  ~
   **
   *  /  %
   +  -
   >>  <<
   &
   ^
   |
   <  <= == >=  >  !=  <>  is
   not
   and 
   or

Các toán tử nằm cùng hàng với nhau có mức độ ưu tiên bằng nhau, khi đó chúng sẽ được thực hiện từ trái qua phải.


print (3 + 5 * 5)
print ((3 + 5) * 5)

print (2 ** 3 * 5)
print (not True or True)
print (not (True or True))

Đoạn code trên ví dụ về mức độ ưu tiên của một số toán tử.

print (2 ** 3 * 5)

Phép lấy lũy thừa có mức độ ưu tiên cao hơn phép nhân. Do đó phép tính 2 ** 3 sẽ được thực hiện trước rồi mới nhân cho 5. Kết quả ra 40.

print (not True or True)

Trong dòng trên, toán tử not có độ ưu tiên cao hơn nên sẽ được thực hiện trước sau đó mới đến toán tử or. Kết quả ra True.

28
40
40
True
False

Các toán tử quan hệ có mức độ ưu tiên cao hơn toán tử boolean.

a = 1
b = 2

if (a > 0 and b > 0):
   print ("a and b are positive integers")

Trong đoạn code trên, toán tử and sẽ được thực hiện sau cùng khi 2 toán tử quan hệ đã thực hiện xong.

a and b are positive integers

Python – Kiểu Dictionary

Trong phần này chúng ta sẽ tìm hiểu sâu hơn về kiểu dữ liệu Dictionary.

Kiểu dictionary là kiểu dữ liệu danh sách, trong đó các phần tử được lưu trữ theo các cặp khóa-giá trị (key-value). Các phần tử trong dictionary không có thứ tự, tức là bạn không thể truy xuất chúng qua chỉ số mà chỉ dùng khóa, ngoài ra vì không có thứ tự nên Python cũng không có sẵn các hàm sắp xếp như hàm sort(), tuy nhiên nếu muốn bạn vẫn có thể tự code lấy hàm sort cho riêng mình. Trong các ngôn ngữ khác thì kiểu dictionary hay được gọi là bảng băm. Trong dictionary không có 2 khóa trùng nhau.

Khởi tạo dictionary

Đầu tiên chúng ta sẽ tìm hiểu cách khởi tạo một dictionary.


weekend = { "Sun": "Sunday", "Mon": "Monday" }
vals = dict(one=1, two=2)

capitals = {}
capitals["svk"] = "Bratislava"
capitals["deu"] = "Berlin"
capitals["dnk"] = "Copenhagen"

d = { i: object() for i in range(4) }

print (weekend)
print (vals)
print (capitals)
print (d)

Đoạn code trên ví dụ về 4 cách để khởi tạo 1 dictionary trong Python.

weekend = { "Sun": "Sunday", "Mon": "Monday" }

Cách đầu tiên và cũng là cách đơn giản nhất. Chúng ta tạo dictionary bằng cách gán dữ liệu trực tiếp. Dictionary được bao bọc bởi cặp dấu ngoặc nhọn {}. Trong đó mỗi phần tử được gán giá trị theo cú pháp key1:value1, key2:value2…, các phần tử phân cách nhau bởi dấu phẩy.

vals = dict(one=1, two=2)

Cách thứ 2 là chúng ta dùng hàm dict().

capitals = {}
capitals["svk"] = "Bratislava"
capitals["deu"] = "Berlin"
capitals["dnk"] = "Copenhagen"

Trên đây là cách thứ 3, đầu tiên chúng ta khởi tạo dict rỗng bằng cặp dấu {}. Sau đó khởi tạo các khóa và gán giá trị, các khóa được tạo trong cặp dấu ngoặc vuông [].

d = { i: object() for i in range(4) }

Cũng giống như kiểu list, dictionary cũng có thể được khởi tạo theo cú pháp comprehension. Cú pháp này có 2 phần, phần đầu tiên là phần biểu thức i: object(), phần thứ 2 là vòng lặp for i in range(4). Tức là cứ mỗi lần lặp, giá trị từ biểu thức sẽ được thêm vào dictionary. Hàm object() khởi tạo một đối tượng kiểu object. Đối tượng này không có giá trị, do đó khi in ra màn hình python sẽ in thông tin về địa chỉ bộ nhớ.

{'Sun': 'Sunday', 'Mon': 'Monday'}
{'two': 2, 'one': 1}
{'svk': 'Bratislava', 'dnk': 'Copenhagen', 'deu': 'Berlin'}
{0: <object object at 0xb76cb4a8>, 1: <object object at 0xb76cb4b0>, 
2: <object object at 0xb76cb4b8>, 3: <object object at 0xb76cb4c0>}

Các phép toán cơ bản

Tiếp theo chúng ta sẽ tìm hiểu về các phép toán cơ bản với dictionary.


basket = { 'oranges': 12, 'pears': 5, 'apples': 4 }

basket['bananas'] = 5

print (basket)
print ("There are %d various items in the basket" % len(basket))

print (basket['apples'])
basket['apples'] = 8
print (basket['apples'])

print (basket.get('oranges', 'undefined'))
print (basket.get('cherries', 'undefined'))

Trong ví dụ trên chúng ta có một dictionary và chúng ta sẽ thực hiện một số phép toán với dict này.

basket = { 'oranges': 12, 'pears': 5, 'apples': 4 }

Đầu tiên chúng ta tạo dict với 3 cặp khóa-giá trị.

basket['bananas'] = 5

Tiếp theo chúng ta tạo thêm 1 cặp khóa-giá trị nữa. Ở đây khóa là bananas còn giá trị là 5.

print ("There are %d various items in the basket" % len(basket))

Chúng ta dùng hàm len() để đếm số lượng các cặp khóa-giá trị.

print (basket['apples'])

Tiếp theo chúng ta in ra màn hình giá trị của khóa apples.

basket['apples'] = 8

Dòng trên thay đổi giá trị của khóa apples thành 8.

print (basket.get('oranges', 'undefined'))

Phương thức get() trả về giá trị của khóa oranges, nếu không có khóa nào có tên như thế thì trả về dòng chữ undefined.

print (basket.get('cherries', 'undefined'))

Dòng trên sẽ trả về undefined vì không có khóa nào tên là cherries.

{'bananas': 5, 'pears': 5, 'oranges': 12, 'apples': 4}
There are 4 various items in the basket
4
8
12
undefined

Tiếp theo chúng ta tìm hiểu về 2 phương thức fromkeys() và setdefault().


basket = ('oranges', 'pears', 'apples', 'bananas')

fruits = {}.fromkeys(basket, 0)
print (fruits)

fruits['oranges'] = 12
fruits['pears'] = 8
fruits['apples'] = 4

print (fruits.setdefault('oranges', 11))
print (fruits.setdefault('kiwis', 11))

print (fruits)

Phương thức fromkeys() tạo một dictionary từ một list, còn phương thức setdefault() trả về giá trị của một khóa, nếu khóa đó không tồn tại thì nó tự động thêm một khóa mới với giá trị mặc định do chúng ta chỉ định.

basket = ('oranges', 'pears', 'apples', 'bananas')

Đầu tiên chúng ta tạo một list các string.

fruits = {}.fromkeys(basket, 0)

Tiếp theo chúng ta dùng phương thức fromkeys() để tạo dictionary từ list trên, trong đó các khóa sẽ là các phần tử của list, còn các giá trị sẽ được gán mặc định là 0. Lưu ý phương thức fromkeys là phương thức của một lớp nên cần được gọi từ tên lớp, trong trường hợp này là {}.

fruits['oranges'] = 12
fruits['pears'] = 8
fruits['apples'] = 4

Ba dòng trên thay đổi giá trị của các khóa trong dict.

print (fruits.setdefault('oranges', 11))
print (fruits.setdefault('kiwis', 11))

Ở 2 dòng trên, dòng đầu tiên sẽ in số 12 ra màn hình vì oranges là khóa đã tồn tại trong dict, dòng thứ 2 sẽ in số 11 ra màn hình vì khóa kiwis chưa tồn tại nên sẽ được tự động thêm vào dict với giá trị mặc định là 11.

{'bananas': 0, 'pears': 0, 'oranges': 0, 'apples': 0}
12
11
{'kiwis': 11, 'bananas': 0, 'pears': 8, 'oranges': 12, 'apples': 4}

Trong ví dụ tiếp theo, chúng ta sẽ tìm hiểu cách nối 2 dictionary với nhau.


domains = { "de": "Germany", "sk": "Slovakia", "hu": "Hungary"}
domains2 = { "us": "United States", "no": "Norway" }

domains.update(domains2)

print (domains)

Để nối 2 dictionary thì chúng ta dùng phương thức update().

domains.update(domains2)

Chúng ta nối domains2 vào domains.

{'sk': 'Slovakia', 'de': 'Germany', 'no': 'Norway', 
'us': 'United States', 'hu': 'Hungary'}

Tiếp theo chúng ta học cách xóa một phần tử ra khỏi dictionary.


items = { "coins": 7, "pens": 3, "cups": 2, 
    "bags": 1, "bottles": 4, "books": 5 }

print (items) 

items.pop("coins")
print (items)

del items["bottles"]
print (items)

items.clear()
print (items)

Trong ví dụ trên, chúng ta có 6 cặp khóa-giá trị, chúng ta sẽ xóa chúng ra khỏi items.

items.pop("coins")

Đầu tiên là phương thức pop(), phương thức này xóa một phần tử trong dictionary theo khóa.

del items["bottles"]

Cách thứ 2 là dùng từ khóa del, dòng code trên sẽ xóa phần tử có khóa bottles ra khỏi dict bằng từ khóa del.

items.clear()

Tiếp theo phương thức clear() có tác dụng xóa toàn bộ phần tử ra khỏi dictionary.

{'bags': 1, 'pens': 3, 'coins': 7, 'books': 5, 'bottles': 4, 'cups': 2}
{'bags': 1, 'pens': 3, 'books': 5, 'bottles': 4, 'cups': 2}
{'bags': 1, 'pens': 3, 'books': 5, 'cups': 2}
{}

Làm việc với khóa và giá trị

Trong phần này chúng ta sẽ tìm hiểu phương thức keys(), values() và items(), phương thức keys() trả về list các khóa có trong dict, phương thức values() trả về list các giá trị, còn phương thức items() trả về list các tuple, trong đó mỗi tuple có 2 phần tử, phần tử đầu tiên là khóa, phần tử thứ 2 là giá trị.

domains = { "de": "Germany", "sk": "Slovakia", "hu": "Hungary",
    "us": "United States", "no": "Norway"  }

print (domains.keys())
print (domains.values())
print (domains.items())

print ("de" in domains)
print ("cz" in domains)

Đoạn code trên ví dụ về cách sử dụng các phương thức đã trình bày ở trên, ngoài ra chúng ta còn dùng thêm từ khóa in.

print (domains.keys())

Dòng trên trả về một list các khóa trong dict bằng phương thức keys().

print (domains.values())

Dòng tiếp theo trả về một list các giá trị trong dict bằng phương thức values().

print (domains.items())

Cuối cùng phương thức items() trả về list các tuple, mỗi tuple chứa 2 phần tử là khóa và giá trị trong dict.

print ("de" in domains)
print ("cz" in domains)

Từ khóa in có tác dụng kiểm tra xem một giá trị nào đó có tồn tại trong dict hay không. Giá trị trả về True hoặc False.

['sk', 'de', 'no', 'us', 'hu']
['Slovakia', 'Germany', 'Norway', 'United States', 'Hungary']
[('sk', 'Slovakia'), ('de', 'Germany'), ('no', 'Norway'), 
('us', 'United States'), ('hu', 'Hungary')]
True
False

Duyệt dictionary

Trong phần này chúng ta sẽ tìm hiểu cách duyệt một dictionary bằng vòng lặp for.


domains = { "de": "Germany", "sk": "Slovakia", "hu": "Hungary",
    "us": "United States", "no": "Norway"  }

for key in domains:
    print (key)
    
for k in domains:
    print (domains[k])
    
for k, v in domains.items():
    print (": ".join((k, v)))

Trong ví dụ trên, chúng ta duyệt 3 lần, mỗi lần duyệt chúng ta lấy khóa, giá trị và cả khóa lẫn giá trị.

for key in domains:
    print (key)

Vòng lặp trên sẽ in ra danh sách các khóa trong dict.

for k in domains:
    print (domains[k])

Vòng lặp trên in ra danh sách cấc giá trị trong list.

for k, v in domains.items():
    print (": ".join((k, v)))

Vòng lặp cuối cùng in ra cả khóa và giá trị.

sk
de
no
us
hu
Slovakia
Germany
Norway
United States
Hungary
sk: Slovakia
de: Germany
no: Norway
us: United States
hu: Hungary

Python – Kiểu List

Bên cạnh String, list cũng là một kiểu dữ liệu quan trọng và trong phần này chúng ta sẽ tìm hiểu sâu hơn về list.

List là một danh sách các phần tử, các phần tử trong một list có thể có nhiều kiểu dữ liệu khác nhau. Các phần tử trong list được lưu trữ theo thứ tự. Giá trị của các phần tử có thể giống nhau.

Các phần tử trong list có thể được truy xuất thông qua chỉ số. Cũng như các kiểu tập hợp khác, chỉ số trong list được đánh số từ 0.


nums = [1, 2, 3, 4, 5]
print (nums)

Trong ví dụ trên, chúng ta có một list có 5 phần tử. List được khởi tạo trong cặp dấu []Các phần tử của list được phân cách bởi dấu phẩy.

[1, 2, 3, 4, 5]

Các phần tử trong một list có thể mang nhiều kiểu dữ liệu khác nhau.


class Being:
    pass

objects = [1, -2, 3.4, None, False, [1, 2], "Python", (2, 3), Being(), {}]
print (objects)

Ví dụ trên tạo ra một list có nhiều kiểu dữ liệu khác nhau, bao gồm kiểu số nguyên, kiểu bool, một string, một tuple, một kiểu từ điển và nguyên cả một list khác.

[1, -2, 3.4, None, False, [1, 2], 'Python', (2, 3), <__main__.Being instance at 0xb76a186c>, {}]

Khởi tạo list

Cách khởi tạo ở trên là cách khởi tạo bằng cách đưa giá trị trực tiếp, ngoài ra bạn có thể khởi tạo mà không cần biết giá trị cụ thể:


n1 = [0 for i in range(15)]
n2 = [0] * 15

print (n1)
print (n2)

n1[0:11] = [10] * 10

print (n1)

Ví dụ trên mô tả hai cách khởi tạo một list. Cách đầu tiên dùng vòng lặp for với cú pháp comprehension bên trong cặp dấu [], cách thứ hai là dùng toán tử *.

n1 = [0 for i in range(15)]
n2 = [0] * 15

Hai dòng code trên ví dụ về cách khởi tạo list dùng toán tử * và cú pháp comprehension, cú pháp comprehension sẽ được giải thích ở gần cuối bài này. Kết quả đều cho ra một list các phần tử có giá trị là 0.

n1[0:11] = [10] * 10

Dòng code trên gán 10 phần tử đầu tiên với giá trị 10.

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 0, 0, 0, 0]

Hàm list()

Hàm list() có tác dụng khởi tạo một list từ một đối tượng tập hợp, có thể là 1 tuple, 1 list khác… hoặc tạo một list rỗng.


a = []
b = list()

print (a == b)

print (list((1, 2, 3)))
print (list("PhoCode"))
print (list(['Ruby', 'Python', 'Perl']))

Trong ví dụ trên, chúng ta khởi tạo một list rỗng, một list từ một string, một list từ một tuple và một list từ một list khác.

a = []
b = list()

Hai dòng trên là 2 cách để khởi tạo một list rỗng.

print (a == b)

Dòng trên sẽ cho ra kết quả True vì và bằng nhau.

print (list((1, 2, 3)))

Dòng trên tạo một list từ một tuple.

print (list("PhoCode"))

Dòng code trên tạo một list từ một string.

print (list(['Ruby', 'Python', 'Perl']))

Cuối cùng là tạo một list từ một list khác.

True
[1, 2, 3]
['Z', 'e', 't', 'C', 'o', 'd', 'e']
['Ruby', 'Python', 'Perl']

Các phép tính trên list

Đoạn code dưới đây ví dụ về các phép tính trên list.

n1 = [1, 2, 3, 4, 5]
n2 = [3, 4, 5, 6, 7]

print (n1 == n2)
print (n1 + n2)

print (n1 * 3)

print (2 in n1)
print (2 in n2)

Chúng ta khởi tạo 2 list gồm các số nguyên và thực hiện một số phép tính.

print (n1 == n2)

Dòng code trên thực hiện phép so sánh thông qua toán tử ==. Kết quả ra False vì các phần tử trong 2 list là khác nhau.

print (n1 + n2)

Toán tử + sẽ gộp hai list lại với nhau và tạo thành một list với chứa các phần tử của 2 list con.

print (n1 * 3)

Toán tử * sẽ nhân số lượng phần tử trong list lên n lần, trong trường hợp trên là 3 lần.

print (2 in n1)

Toán tử in kiểm tra xem một giá trị nào đó có tồn tại trong list hay không. Giá trị trả về là True hoặc False.

False
[1, 2, 3, 4, 5, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
True
False

Một số hàm dùng với list


n = [1, 2, 3, 4, 5, 6, 7, 8]

print ("There are %d items" % len(n))
print ("Maximum is %d" % max(n))
print ("Minimum is %d" % min(n))
print ("The sum of values is %d" % sum(n))

Đoạn code trên ví dụ về tác dụng của bốn hàm len(), max(), min(), và sum().

print ("There are %d items" % len(n))

Hàm len() lấy độ dài của một list.

print ("Maximum is %d" % max(n))
print ("Minimum is %d" % min(n))

Hàm max() và min() tìm giá trị lớn nhất và nhỏ nhất có trong list, tất nhiên là trong trường hợp các phần tử trong list phải có cùng kiểu dữ liệu, nếu không sẽ báo lỗi.

print ("The sum of values is %d" % sum(n))

Hàm sum() trả về tổng các giá trị của các phần tử trong list, chỉ có thể dùng khi list chứa các phần tử kiểu số.

There are 8 items
Maximum is 8
Minimum is 1
The sum of values is 36

Thêm phần tử mới vào list


langs = list()

langs.append("Python")
langs.append("Perl")
print (langs)

langs.insert(0, "PHP")
langs.insert(2, "Lua")
print (langs)

langs.extend(("JavaScript", "ActionScript"))
print (langs)

Có 3 phương thức để thêm một phần tử vào list, đó là các phương thức append(), insert() và extend().

langs.append("Python")
langs.append("Perl")

Phương thức append() thêm một phần tử vào cuối list.

langs.insert(0, "PHP")
langs.insert(2, "Lua")

Phương thức insert() có thể thêm phần tử vào vị trí bất kì trong list.

langs.extend(("JavaScript", "ActionScript"))

Trong khi phương thức append() chỉ thêm một phần tử vào cuối list thì phương thức extend() có thể thêm một dãy các phần tử vào cuối list.

['Python', 'Perl']
['PHP', 'Python', 'Lua', 'Perl']
['PHP', 'Python', 'Lua', 'Perl', 'JavaScript', 'ActionScript']

Lỗi IndexError, TypeError

Lỗi exception IndexError là lỗi khi chúng ta thực hiện các thao tác có sử dụng chỉ số mà chỉ số vượt ngoài phạm vi list. Loại lỗi exception sẽ được đề cập ở các bài sau.

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

try:
    n[0] = 10
    n[6] = 60    
except IndexError as e:
    (print e)

Trong ví dụ trên, chúng ta có một list có 5 phần tử, các phần tử được đánh số từ 0..4

n[6] = 60

Nếu chúng ta truy xuất phần tử vượt quá 4 thì lỗi IndexError sẽ xảy ra, trong ví dụ trên chúng ta truy xuất phần tử thứ 6.

list assignment index out of range

Một lỗi exception khác là TypeError, lỗi này xảy ra khi chỉ số chúng ta đưa vào không phải là kiểu số.


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

try:
    print (n[1])
    print (n['2']  ) 
except TypeError as e:
    print ("Error in file %s" % __file__)
    print ("Message: %s" % e)

Ví dụ trên sẽ xảy ra lỗi TypeError.

print (n['2'])

Chỉ số bắt buộc phải là kiểu số, tất cả các kiểu dữ liệu còn lại đều không hợp lệ.

2
Error in file ./typeerror.py
Message: list indices must be integers, not str

Xóa phần tử trong list


langs = ["Python", "Ruby", "Perl", "Lua", "JavaScript"]
print (langs)

langs.pop(3)
langs.pop()
print (langs)

langs.remove("Ruby")
print (langs)

Chúng ta có hai phương thức để xóa phần tử trong một list là phương thức pop() và phương thức remove(). Phương thức pop() xóa phần tử thông qua chỉ số, phương thức remove() xóa phần tử thông qua giá trị.

langs.pop(3)
langs.pop()

Ở đoạn code trên chúng ta xóa phần tử có chỉ số là 3, nếu chúng ta không đưa chỉ số vô thì  Python sẽ tự động xóa phần tử cuối cùng.

langs.remove("Ruby")

Dòng trên xóa phần tử theo giá trị, phần tử đầu tiên trong list có giá trị “Ruby” sẽ bị xóa.

['Python', 'Ruby', 'Perl', 'Lua', 'JavaScript']
['Python', 'Ruby', 'Perl']
['Python', 'Perl']

Ngoài ra chúng ta có thể xóa phần tử của list bằng từ khóa del.


langs = ["Python", "Ruby", "Perl", "Lua", "JavaScript"]
print (langs)

del langs[1]
print (langs)

#del langs[15]

del langs[:]
print (langs)

Trong ví dụ trên chúng ta có một list các string, chúng ta sẽ xóa các phần tử bằng từ khóa del.

del langs[1]

Dòng trên xóa phần tử thứ 1.

#del langs[15]

Nếu chúng ta xóa các phần tử có chỉ số vượt ngoài phạm vi của list thì lỗi IndexError sẽ xảy ra.

del langs[:]

Dòng code trên xóa toàn bộ list.

['Python', 'Ruby', 'Perl', 'Lua', 'JavaScript']
['Python', 'Perl', 'Lua', 'JavaScript']
[]

Thay đổi giá trị phần tử trong list


langs = ["Python", "Ruby", "Perl"]

langs.pop(2)
langs.insert(2, "PHP")
print (langs)

langs[2] = "Perl"
print (langs)

Đoạn code trên sửa đổi giá trị của phần tử cuối cùng trong list.

langs.pop(2)
langs.insert(2, "PHP")

Trong hai dòng code trên, chúng ta xóa phần tử cuối cùng sau đó thêm một phần tử mới vào, cách này khá rườm rà và mất thời gian.

langs[2] = "Perl"

Thay vào đó bạn chỉ đơn giản là gán cho phần tử đó một giá trị mới là được.

['Python', 'Ruby', 'PHP']
['Python', 'Ruby', 'Perl']

Sao chép một list


import copy

w = ["Python", "Ruby", "Perl"]

c1 = w[:]
c2 = list(w)
c3 = copy.copy(w)
c4 = copy.deepcopy(w)
c5 = [e for e in w]

c6 = []
for e in w:
    c6.append(e)
    
c7 = []
c7.extend(w)

print (c1, c2, c3, c4, c5, c6, c7)

Đoạn code trên chúng ta có một list chứa 3 string. Chúng ta sao chép list này sang 7 list khác.

import copy

Trong Python có module copy, module này có 2 phương thức dùng cho việc sao chép.

c1 = w[:]

Cách một bạn dùng cú pháp như trên sẽ copy được một list.

c2 = list(w)

Cách thứ 2 là dùng hàm list() để khởi tạo ngay một list.

c3 = copy.copy(w)
c4 = copy.deepcopy(w)

Cả hai phương thức copy() deepcopy() đều có tác dụng là tạo ra bản sao của một list. Đến đây nếu bạn không muốn nghe giải thích về sự khác nhau của 2 phương thức này thì có thể bỏ qua đoạn dưới vì cũng không cần thiết lắm :D.

Nếu đã từng học hướng đối tượng thì bạn đã biết là một đối tượng có một phần bộ nhớ dành riêng cho chúng trong máy tính. Khi chúng ta tạo một list trong Python, chẳng hạn như a = [1, 2, 3], một ô nhớ sẽ được cấp cho biến a để lưu trữ thông tin về 3 phần tử của nó, và 3 ô nhớ riêng được cấp cho 3 phần tử của list a. Khi chúng ta dùng phương thức copy(), vd b = copy.copy(a), thì biến b được cấp một vùng nhớ riêng, còn 3 phần tử của biến b cũng được cấp vùng nhớ nhưng chúng không trực tiếp lưu trữ giá trị như biến mà bản thân chúng là một con trỏ tham chiếu đến 3 phần tử của biến a. Còn nếu dùng phương thức deepcopy() thì biến cũng được cấp một vùng nhớ riêng, và 3 phần tử của biến b cũng được cấp vùng nhớ riêng và lưu trữ giá trị giống như biến a, có nghĩa là lúc này chúng là các thực thể độc lập, không liên quan đến nhau.

c5 = [e for e in w]

Đoạn code trên tạo ra một bản copy khác bằng cách dùng vòng lặp.

c6 = []
for e in w:
    c6.append(e)

Dòng trên cũng không có gì khó hiểu.

c7 = []
c7.extend(w)

Phương thức extend cũng có thể được dùng để tạo bản sao.

['Python', 'Ruby', 'Perl'] ['Python', 'Ruby', 'Perl'] ['Python', 'Ruby', 'Perl'] 
['Python', 'Ruby', 'Perl'] ['Python', 'Ruby', 'Perl'] ['Python', 'Ruby', 'Perl'] 
['Python', 'Ruby', 'Perl']

Chỉ số trong list

Như chúng ta đã biết, chúng ta có thể truy xuất phần tử thông qua chỉ số. Chỉ số trong Python được đánh số từ 0. Ngoài ra chúng ta có thể dùng chỉ số âm để lấy lùi.


n = [1, 2, 3, 4, 5, 6, 7, 8]

print (n[0])
print (n[-1])
print (n[-2])

print (n[3])
print (n[5])

Chỉ số được đặt bên trong cặp dấu [].

1
8
7
4
6

Phương thức index(e, start, end) tìm xem có phần tử nào có giá trị giống như tham số hay không trong phạm vi từ start đến end. Chúng ta có thể không cần đưa hai tham số sau vào và Python sẽ tự ngầm tìm từ đầu đến cuối list.


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

print (n.index(1))
print (n.index(2))

print (n.index(1, 1))
print (n.index(2, 2))

print (n.index(1, 2, 5))
print (n.index(3, 4, 8))

Đoạn code trên ví dụ về phương thức index().

print (n.index(1))
print (n.index(2))

Hai dòng code trên tìm vị trí của phần tử đầu tiên có giá trị 1 và 2.

print (n.index(1, 1))
print (n.index(2, 2))

Hai dòng code trên cũng tìm phần tử có giá trị 1 và 2 bắt đầu từ vị trí số 1.

print (n.index(1, 2, 5))

Đoạn code trên tìm phần tử có giá trị 1 trong phạm vi từ 2 đến 5.

0
1
4
5
4
6

Duyệt chuỗi

Tiếp theo chúng ta sẽ tìm hiểu cách duyệt một chuỗi.


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

for e in n:
    print (e,)
    
print ()  

Đoạn code trên duyệt chuỗi bằng vòng lặp for khá đơn giản.

1 2 3 4 5

Đoạn code dưới đây hơi rườm rà hơn một tí.


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

i = 0
s = len(n)

while i < s:
    print (n[i],)
    i = i + 1

print()   

Chúng ta duyệt qua chuỗi bằng vòng lặp while.

i = 0
l = len(n)

Đầu tiên chúng ta định nghĩa biến đếm và biến lưu trữ chiều dài của list.

while i < s:
    print (n[i],)
    i = i + 1

Cứ mỗi lần lặp, chúng ta tăng biến đếm lên.

Khi dùng vòng lặp for với hàm enumerate(), chúng ta có thể lấy được cả chỉ số và giá trị của các phần tử trong list.


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

for e, i in enumerate(n):
    print ("n[%d] = %d" % (e, i))
n[0] = 1
n[1] = 2
n[2] = 3
n[3] = 4
n[4] = 5

Đếm số lượng phần tử trong list

Không những đếm số lượng phần tử của list mà còn đếm số lần xuất hiện của các phần tử nhất định trong list.


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

print (n.count(4))
print (n.count(1))
print (n.count(2))
print (n.count(6))

Chúng ta dùng phương thức count(), trong ví dụ trên, chúng ta đếm số lần xuất hiện của một vài chữ số trong list.

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

Chúng ta tạo ra một list. Trong đó số 1 và số 4 được xuất hiện nhiều lần.

print (n.count(4))
print (n.count(1))
print (n.count(2))
print (n.count(6))

Ở đây chúng ta đếm số lần xuất hiện của số 4, 1, 2, và 6.

3
2
1
0

Lồng các list lại với nhau

Một list không chỉ chứa các phần tử đơn lẻ mà có thể chứa nguyên cả một list khác.

nums = [[1, 2], [3, 4], [5, 6]]

print (nums[0])
print (nums[1])
print (nums[2])

print (nums[0][0])
print (nums[0][1])

print (nums[1][0])
print (nums[2][1])

print (len(nums))

Trong ví dụ trên, chúng ta tạo ra một list chứa 3 list khác.

print (nums[0][0])
print (nums[0][1])

Để truy xuất phần tử của list con thì chúng ta dùng hai cặp dấu ngoặc vuông [].

[1, 2]
[3, 4]
[5, 6]
1
2
3
6
3

Đoạn code dưới đây lồng 4 list lại với nhau.


nums = [[1, 2, [3, 4, [5, 6]]]]

print (nums[0])
print (nums[0][2])
print (nums[0][2][2])

print (nums[0][0])
print (nums[0][2][1])
print (nums[0][2][2][0])
print (nums[0][0])
print (nums[0][2][1])
print (nums[0][2][2][0])

Để truy xuất các phần tử con thì chúng ta cứ dùng thêm các cặp dấu ngoặc vuông []. 

[1, 2, [3, 4, [5, 6]]]
[3, 4, [5, 6]]
[5, 6]
1
4
5

Sắp xếp list


n = [3, 4, 7, 1, 2, 8, 9, 5, 6]
print (n)

n.sort()
print (n)

n.sort(reverse=True)
print (n)

Trong ví dụ trên, chúng ta có một list chứa các con số không theo một thứ tự nào cả. Chúng ta sẽ sắp xếp chúng bằng phương thức sort(). 

n.sort()

Mặc định phương thức sort() sẽ sắp xếp từ bé đến lớn.

n.sort(reverse=True)

Nếu muốn sắp xếp theo chiều ngược lại, bạn cho tham số reverse là True.

[3, 4, 7, 1, 2, 8, 9, 5, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[9, 8, 7, 6, 5, 4, 3, 2, 1]

Phương thức sort() thay đổi chính list gốc, nếu bạn không muốn thay đổi list gốc mà chỉ muốn có một bản copy list mới đã được sắp xếp thì dùng phương thức sorted().


n = [3, 4, 1, 7, 2, 5, 8, 6]

print (n)
print (sorted(n))
print (n)
[3, 4, 1, 7, 2, 5, 8, 6]
[1, 2, 3, 4, 5, 6, 7, 8]
[3, 4, 1, 7, 2, 5, 8, 6]

Đảo ngược list

a1 = ["bear", "lion", "tiger", "eagle"]

a1.reverse()
print (a1)

Để đảo ngược một list thì chúng ta dùng phương thức reverse().

['eagle', 'tiger', 'lion', 'bear']

Khởi tạo list bằng comprehension

Comprehension là một kiểu cú pháp dùng khi khởi tạo list từ một list khác. Bạn đã thấy cú pháp này ở các phần trên và trong các bài trước.

L = [<biểu thức> for <biến> in <danh sách> [câu lệnh if]]

Đoạn code mã giả trên là cú pháp comprehension. Khi chúng ta khởi tạo list theo cú pháp này. Một vòng for sẽ lặp qua danh sách cho trước, cứ mỗi lần lặp, nó sẽ kiểm tra xem nếu câu lệnh if có thỏa điều kiện không, nếu thỏa thì thực hiện biểu thức và gán giá trị trả về của biểu thức cho list L.

a = [1, 2, 3, 4, 5, 6, 7, 8, 9] 
b = [e + 2 for e in a if e % 2] 
print (b)

Trong ví dụ trên, chúng ta tạo list gồm các con số. Chúng ta tạo một list gồm các phần tử là các số nguyên không thể chia hết cho 2 trong list và cộng thêm 2 cho số đó.

b = [e + 2 for e in a if e % 2]

Trong vòng lặp for, mỗi lần lặp sẽ kiểm tra xem nếu e có chia hết cho 2 hay không, nếu không thì thực hiện biểu thức, biểu thức ở đây là cộng e thêm 2, sau đó thêm vào list b.

Cú pháp comprehension có thể viết một cách tường minh lại như sau:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

b = list()
for e in a:
    if (e % 2):
       b.append(e + 2)
 
print (b)

Đoạn code trên tương đường với cú pháp comprehension.

[3, 5, 7, 9, 11]

Hàm map() và hàm filter()

Hai hàm map() và filter() là hai hàm có tác dụng thực thi các câu lệnh trên các phần tử của list và trả về một list mới. Hai hàm này có tác dụng tương tự như cú pháp comprehension. Hiện tại thì người ta có xu hướng dùng cú pháp comprehension nhiều hơn do tính hữu dụng của nó.

def to_upper(s):
    return s.upper()

words = ["stone", "cloud", "dream", "sky"]

words2 = map(to_upper, words)
print (words2)

Hàm map() có tác dụng thực thi một hàm khác lên từng phần tử của một list.

def to_upper(s):
    return s.upper()

Trong ví dụ trên thì đây là hàm mà chúng ta sẽ dùng để thực thi cho các phần tử của list. Ở đây chúng ta viết hoa một string cho trước.

words2 = map(to_upper, words)
print (words2)

Tham số đầu tiên của hàm map() là tên của hàm sẽ được thực thi, tham số thứ hai là list nguồn.

['STONE', 'CLOUD', 'DREAM', 'SKY']

Hàm filter() cũng thực thi một hàm nhưng không làm gì với list gốc cả mà chỉ đơn giản là lấy các phần tử của list gốc nếu chúng thỏa điều kiện nào đó.

def positive(x):
    return x > 0

n = [-2, 0, 1, 2, -3, 4, 4, -1]

print (filter(positive, n))

Trong ví dụ trên, chúng ta tạo một list có các số nguyên. Hàm filter() sẽ lọc ra các phần tử > 0 bằng hàm positive().

def positive(x):
    return x > 0

Đoạn code trên là hàm do chúng ta định nghĩa, hàm này sẽ được sử dụng bởi hàm filter(). Giá trị trả về của hàm này là một kiểu bool.

[1, 2, 4, 4]