Dict và Tệp Python

Bảng băm nhỏ

Cấu trúc bảng băm giá trị/khoá hiệu quả của Python được gọi là một "dict". Nội dung của lệnh dict có thể được viết dưới dạng một chuỗi cặp khoá:giá trị trong dấu ngoặc nhọn { }, ví dụ: dict = {key1:value1, key2:value2, ... }. "Empty dict" chỉ là một cặp dấu ngoặc nhọn {} trống.

Việc tra cứu hoặc đặt giá trị trong một dict sử dụng dấu ngoặc vuông, ví dụ: dict['foo'] tra cứu giá trị theo khoá 'foo'. Chuỗi, số và bộ dữ liệu hoạt động như khoá và mọi kiểu đều có thể là một giá trị. Các loại khác có thể hoạt động đúng cách hoặc không hoạt động đúng cách dưới dạng khoá (chuỗi và bộ dữ liệu hoạt động hiệu quả vì không thể thay đổi). Việc tra cứu một giá trị không có trong tập hợp từ điển sẽ gửi một lỗi KeyError – hãy sử dụng "in" để kiểm tra xem khoá có trong tập hợp từ điển hay không, hoặc sử dụng dict.get(key) để trả về giá trị hoặc None nếu không có khoá (hoặc get(key, not-found) cho phép bạn chỉ định giá trị cần trả về trong trường hợp không tìm thấy).

  ## Can build up a dict by starting with the empty dict {}
  ## and storing key/value pairs into the dict like this:
  ## dict[key] = value-for-that-key
  dict = {}
  dict['a'] = 'alpha'
  dict['g'] = 'gamma'
  dict['o'] = 'omega'

  print(dict) ## {'a': 'alpha', 'o': 'omega', 'g': 'gamma'}

  print(dict['a'])     ## Simple lookup, returns 'alpha'
  dict['a'] = 6       ## Put new key/value into dict
  'a' in dict         ## True
  ## print(dict['z'])                  ## Throws KeyError
  if 'z' in dict: print(dict['z'])     ## Avoid KeyError
  print(dict.get('z'))  ## None (instead of KeyError)

dict với các khoá 'a' 'o' 'g'

Theo mặc định, vòng lặp for trên từ điển sẽ lặp lại các khoá của từ điển đó. Các khoá sẽ xuất hiện theo thứ tự tuỳ ý. Các phương thức dict.keys() và dict.values() trả về danh sách các khoá hoặc giá trị một cách rõ ràng. Ngoài ra, còn có items() trả về danh sách các cặp (khoá, giá trị). Đây là cách hiệu quả nhất để kiểm tra tất cả dữ liệu khoá-giá trị trong từ điển. Tất cả danh sách này có thể được truyền đến hàmsort().

  ## By default, iterating over a dict iterates over its keys.
  ## Note that the keys are in a random order.
  for key in dict:
    print(key)
  ## prints a g o

  ## Exactly the same as above
  for key in dict.keys():
    print(key)

  ## Get the .keys() list:
  print(dict.keys())  ## dict_keys(['a', 'o', 'g'])

  ## Likewise, there's a .values() list of values
  print(dict.values())  ## dict_values(['alpha', 'omega', 'gamma'])

  ## Common case -- loop over the keys in sorted order,
  ## accessing each key/value
  for key in sorted(dict.keys()):
    print(key, dict[key])

  ## .items() is the dict expressed as (key, value) tuples
  print(dict.items())  ##  dict_items([('a', 'alpha'), ('o', 'omega'), ('g', 'gamma')])

  ## This loop syntax accesses the whole dict by looping
  ## over the .items() tuple list, accessing one (key, value)
  ## pair on each iteration.
  for k, v in dict.items(): print(k, '>', v)
  ## a > alpha    o > omega     g > gamma

Lưu ý về chiến lược: xét về hiệu suất, từ điển là một trong những công cụ hiệu quả nhất và bạn nên sử dụng từ điển khi có thể để dễ dàng sắp xếp dữ liệu. Ví dụ: bạn có thể đọc một tệp nhật ký, trong đó mỗi dòng bắt đầu bằng một địa chỉ IP và lưu trữ dữ liệu vào một tập hợp từ điển bằng cách sử dụng địa chỉ IP làm khoá và danh sách các dòng mà địa chỉ IP đó xuất hiện dưới dạng giá trị. Sau khi đọc toàn bộ tệp, bạn có thể tra cứu bất kỳ địa chỉ IP nào và ngay lập tức xem danh sách các dòng của địa chỉ đó. Từ điển thu thập dữ liệu rời rạc và biến dữ liệu đó thành một nội dung nhất quán.

Định dạng từ điển

Toán tử % hoạt động thuận tiện để thay thế các giá trị từ một dict vào một chuỗi theo tên:

  h = {}
  h['word'] = 'garfield'
  h['count'] = 42
  s = 'I want %(count)d copies of %(word)s' % h  # %d for int, %s for string
  # 'I want 42 copies of garfield'

  # You can also use str.format().
  s = 'I want {count:d} copies of {word}'.format(h)

Xóa

Toán tử "del" thực hiện việc xoá. Trong trường hợp đơn giản nhất, phương thức này có thể xoá định nghĩa của một biến, như thể biến đó chưa được xác định. Bạn cũng có thể sử dụng Del trên các phần tử danh sách hoặc lát cắt để xoá phần đó của danh sách và xoá các mục nhập khỏi từ điển.

  var = 6
  del var  # var no more!

  list = ['a', 'b', 'c', 'd']
  del list[0]     ## Delete first element
  del list[-2:]   ## Delete last two elements
  print(list)      ## ['b']

  dict = {'a':1, 'b':2, 'c':3}
  del dict['b']   ## Delete 'b' entry
  print(dict)      ## {'a':1, 'c':3}

Files

Hàm open() mở và trả về một handle tệp có thể dùng để đọc hoặc ghi tệp theo cách thông thường. Mã f = open('name', 'r') mở tệp vào biến f, sẵn sàng cho các thao tác đọc và sử dụng f.close() khi hoàn tất. Thay vì "r", hãy sử dụng "w" để ghi và "a" để nối. Tiêu chuẩn cho vòng lặp hoạt động đối với các tệp văn bản, lặp lại qua các dòng của tệp (điều này chỉ áp dụng cho các tệp văn bản, không áp dụng cho tệp nhị phân). Kỹ thuật vòng lặp for là một cách đơn giản và hiệu quả để xem tất cả các dòng trong tệp văn bản:

  # Echo the contents of a text file
  f = open('foo.txt', 'rt', encoding='utf-8')
  for line in f:   ## iterates over the lines of the file
    print(line, end='')    ## end='' so print does not add an end-of-line char
                           ## since 'line' already includes the end-of-line.
  f.close()

Việc đọc một dòng tại một thời điểm có chất lượng tốt vì không phải tất cả tệp đều cần vừa với bộ nhớ tại một thời điểm – rất tiện lợi nếu bạn muốn xem mọi dòng trong tệp 10 gigabyte mà không cần sử dụng 10 gigabyte bộ nhớ. Phương thức f.readlines() đọc toàn bộ tệp vào bộ nhớ và trả về nội dung của tệp dưới dạng danh sách các dòng. Phương thức f.read() sẽ đọc toàn bộ tệp thành một chuỗi duy nhất. Đây có thể là cách thuận tiện để xử lý toàn bộ văn bản cùng một lúc, chẳng hạn như với các biểu thức chính quy mà chúng ta sẽ thấy sau.

Đối với hoạt động ghi, phương thức f.write(string) là cách dễ nhất để ghi dữ liệu vào tệp đầu ra đang mở. Hoặc bạn có thể sử dụng "print" với một tệp đang mở như "print(string, file=f)".

Tệp Unicode

Để đọc và ghi các tệp được mã hoá bằng unicode, hãy sử dụng chế độ "t" và chỉ định rõ ràng một bộ mã hoá:


with open('foo.txt', 'rt', encoding='utf-8') as f:
  for line in f:
    # here line is a *unicode* string

with open('write_test', encoding='utf-8', mode='wt') as f:
    f.write('\u20ACunicode\u20AC\n') #  €unicode€
    # AKA print('\u20ACunicode\u20AC', file=f)  ## which auto-adds end='\n'

Thực hành phát triển gia tăng

Khi xây dựng một chương trình Python, đừng viết toàn bộ chương trình trong một bước. Thay vào đó, hãy chỉ xác định một mốc đầu tiên, ví dụ: "bước đầu tiên là trích xuất danh sách từ". Viết mã để đạt được mốc đó và chỉ in cấu trúc dữ liệu tại thời điểm đó, sau đó bạn có thể thực hiện sys.exit(0) để chương trình không chạy trước vào các phần chưa hoàn tất. Sau khi mã mốc quan trọng hoạt động, bạn có thể xử lý mã cho mốc quan trọng tiếp theo. Việc có thể xem kết quả in của các biến ở một trạng thái có thể giúp bạn suy nghĩ về cách cần chuyển đổi các biến đó để chuyển sang trạng thái tiếp theo. Python rất nhanh với mẫu này, cho phép bạn thực hiện một chút thay đổi và chạy chương trình để xem cách hoạt động của chương trình. Hãy tận dụng thời gian quay vòng nhanh chóng đó để xây dựng chương trình của bạn theo từng bước nhỏ.

Bài tập: wordcount.py

Kết hợp tất cả tài liệu cơ bản về Python – chuỗi, danh sách, tập hợp, bộ dữ liệu, tệp – hãy thử bài tập tóm tắt wordcount.py trong phần Bài tập cơ bản.