Namedtuple trong Python (Namedtuple in Python)

Image result for namedtuple
nguồn: Corey Schafer


Các bạn cũng đã biết trong Python, chúng ta có rất nhiều kiểu dữ liệu cho phép chúng ta lưu trữ các dữ liệu chúng ta muốn. Điển hình như Tuple
>>> teo = ('Teo', 'student', ['CF', 'Dota'])
>>> teo
('Teo', 'student', ['CF', 'Dota'])
>>> teo[0], teo[2]                             # access by position
('Teo', ['CF', 'Dota'])
Tuy vậy các số chỉ vị trí của các tuples (field numbers) vẫn có đôi chút gây cho chúng ta khó hiểu hơn là các từ khóa (names of keys) trong dictionary. Ví dụ sau đây sử dụng dict thay cho tuple
>>> teo = dict(name='Teo', job='student', favgames=['CF', 'Dota'])
>>> teo
{'name': 'Teo', 'job': 'Student', 'favgames': ['CF', 'Dota']}
>>> teo['name'], teo['favgames']               # access by key
('Teo', ['CF', 'Dota'])
Chúng ta cũng có thể chuyển đổi từ dictionary sang tuple nếu cần thiết.
>>> tuple(teo.values())                   # Values tu tuple
('Teo', 'Student', ['CF', 'Dota'])
>>> list(teo.items())                     # Items to tuple list
[('name', 'Teo'), ('job', 'Student'), ('favgames', ['CF', 'Dota'])]
Đương nhiên chúng ta cũng có một kiểu đối tượng giúp ta lưu trữ và truy cập (access) đến các giá trị dựa vào cả vị trí (position) và tên (name). Đó chính là namedtuple và ở bài viết này, mình sẽ giới thiệu với các bạn

Table of content

- Giới thiệu về namedtuple
- Cách namedtuple làm việc
- Một số methods và Attributes của namedtuple
- Lưu ý với namedtuple
- Khi nào thì nên dùng namedtuple?
- Lời kết

Giới thiệu về namedtuple

namedtuple có trong collections, một module nằm trong thư viện chuẩn của Python (standard library). namedtuple cho phép chúng ta trụy cập đến giá trị bằng vị trí (position) và thuộc tính tên (name)

Cách namedtuple làm việc

Prototype: collections.namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)
>>> from collections import namedtuple         # import extension type
>>> person = namedtuple(‘Person’, [‘name’, ‘job’, ‘favgames’])
>>> teo = person(‘Teo’, ‘student’, [‘CF’, ‘Dota’])
>>> teo
Person(name='Teo', job='student', favgames=['CF', 'Dota'])
>>> teo[0], teo[2]                  # access by position
('Teo', ['CF', 'Dota'])
>>> teo.name, teo.favgames          # access by attribute
('Teo', ['CF', 'Dota'])
typename chính là 'Person'. Nó giúp chúng ta phân biệt được dữ liệu mà chúng ta sẽ lưu liên quan về điều gì. Nếu bạn muốn lưu trữ dữ về các con vật, các bạn có thể đặt typename'Animal', về các ngôn ngữ lập trình thì có thể là 'Programming_Language'.
Lưu ý là cách đặt tên typename cũng tương tự nhiên một biến.

Phần tiếp theo là field_names. Đây chính là các thuộc tính của typename. Ví dụ typename'Idol_JAV' thì các field_names có thể là 'country', 'so_do_3_vong', ..
Các field_names cũng có cách đặt tên tương tự như tên biến
Các bạn có thể truyền field_names theo ['field_name1', 'field_name2', ..] như ở trên ví dụ hoặc cũng có thể là 'field_name1, field_name2'. Nhưng mình vẫn nghĩ cách sau tiện lợi hơn đó là 'field_name1 field_name2'. namedtuple sẽ tự động xử lí field_names mà ta truyền vào bằng cách field_names.replace(',', ' ').split().

Về 3 keyword onlye parameters còn lại mà mình không sử dụng trong ví dụ vì nó không mấy quan trọng lắm nhưng mình cũng sẽ nói sơ qua.

+ verbose mặc định nhận giá trị False. Nếu như chúng ta truyền vào với giá trị True
>>> person = namedtuple('Person', 'name job favgames', verbose=True)
Thì namedtuple sẽ in ra chúng ta định nghĩa của class mới được tạo đó. gồm các attributes và methods dựa vào typename và field_names bạn cung cấp.

+ rename nếu được nhận giá trị là True thì nó sẽ giúp chúng ta sửa các field_names không hợp lệ (invalid) thành các vị trí nhờ vào enumerate được sử dụng trong namedtuple.
 ... names[i] = '_%d' % i
Ví dụ như ta truyền field_names['abc', 'def', 'ghi', 'abc']. namedtuple sẽ kiểm tra các fields này xem có hợp lệ hay không. Nếu như nó bị trùng với reserved words hoặc là duplicate. Như ví dụ của chúng ta thì 'def' bị trùng với từ khóa của Python, còn 'abc' ở vị trí 3 bị trùng với 'abc' ở vị trí 0 do đó namedtuple sẽ chuyển đổi lại thành ['abc', '_1', 'ghi', '_3']

+ module nếu khác None thì thuộc tính __module__ của lớp (class) đó sẽ nhận giá trị được cho
>>> person = namedtuple('Person', 'name job favgames', module='attribute of module')
>>> person.__module__
'attribute of module'
Đi sâu hơn vào ví dụ. Chúng ta tạo một lớp (class) person nhờ vào namedtuple. Sau đó chúng ta tạo một đối tượng (object) là teo với các attributes được truyền vào lần lượt là 'Teo', 'student', ['CF', 'Dota'] cho name, job, favgames.
Và một lẽ đương nhiên vì nó là positional or keyword parameters nên các bạn hoàn toàn có thể
>>> teo = person(job='student', favgames=['CF', 'Dota'], name='Teo')
Cũng có thể sử dụng unpacking arguments
>>> TeosInfor = ('Teo', 'student', ['CF', 'Dota'])
>>> teo = person(*TeosInfor)
>>> teo
Person(name='Teo', job='student', favgames=['CF', 'Dota'])
>>> TisInfor = {'name': 'Ti', 'job': 'gangster', 'favgames': ['Gunny', 'Vo Lam', 'JAV']}
>>> ti = person(**TisInfor)
>>> ti
Person(name='Ti', job='gangster', favgames=['Gunny', 'Vo Lam', 'JAV'])
Các bạn cũng thấy được rằng chúng ta có thể truy cập tới thuộc tính (attribute) của đối tượng bằng cách sử dụng vị trí như tuple hoặc sử dụng tên (names/ keys) như dictionary.
Ngoài ra ta còn có thể lấy hoặc xuất ra toàn bộ các giá trị attributes của đối tượng
>>> name, job, favourite_games = teo
>>> name, job, favourite_games
('Teo', 'student', ['CF', 'Dota'])
>>> for value in teo: print(value)
… kết quả in ra được là Teo, student, ['CF', 'Dota']

Một số methods và Attributes của namedtuple

Dưới đây là một số methodsattributes của class mà do namedtuple tạo ra.

Methods

Prototype:  somenamedtuple._make(iterable)
>>> infor = ('Yui Hatano', 'AV Idol', ['Blow job', 'Doggy'])
>>> person._make(infor)
Person(name='Yui Hatano', job='AV Idol', favgames=['Blow job', 'Doggy'])
Tạo ra một đối tượng có các attributes dựa vào iterable. Cũng tương tự như lúc bạn unpack arguments.

Prototype: somenamedtuple._asdict()
>>> infor = ('Yui Hatano', 'AV Idol', ['Blow job', 'Doggy'])
>>> Yui = person._make(infor)
>>> Yui._asdict()
OrderedDict([('name', 'Yui Hatano'), ('job', 'AV Idol'), ('favgames', ['Blow job', 'Doggy'])])
>>> for key, value in Yui._asdict().items(): print(key, ':', value)
name : Yui Hatano
job : AV Idol
favgames : ['Blow job', 'Doggy']
Trả về một OrderedDict với các field_names và giá trị của nó gói trong một tuple.
Prototype: somenamedtuple._replace(**kwargs)
>>> Yui._replace(job='Wife', favgames='Cooking')
Person(name='Yui Hatano', job='Wife', favgames='Cooking')
>>> Yui
Person(name='Yui Hatano', job='AV Idol', favgames=['Blow job', 'Doggy'])
Trả về một đối tượng mới với các attributes chỉ định bị thay đổi bằng các giá trị mới.

Attributes

somenamedtuple._source
Trả về một đoạn source code trần trụi mà từ đó ta có thể dùng để viết một class namedtuple tương tự. Có thể được in ra, thực thì bằng cách sử dụng exec() hoặc có thể sao lưu lại ra file.
somenamedtuple._fields
Trả về các attributes của class và đặt ngăn nắp trong một tuple.
>>> person._fields
('name', 'job', 'favgames')
>>> Yui._fields
('name', 'job', 'favgames')

Lưu ý với namedtuple

Có thể thấy tuple hiện hữa trong namedtuple. Do đó namedtuple cũng thừa hưởng được một đức tích đó là không thay lòng đổi dạ. Bạn không thể thay thế được giá trị của các attributes của đối tượng thuộc class do namedtuple tạo ra.
>>> Yui.name = 'Miku Ohashi'
Traceback (most recent call last):
 File "", line 1, in 
AttributeError: can't set attribute

Khi nào thì nên dùng namedtuple?

Theo mình thì bạn nên sử dụng nó thay cho tuple truyền thống khi mà bạn nghĩ nó sẽ giúp code bạn trở nên rõ ràng và dễ đọc hơn nhờ sự kết hợp tinh hoa giữa dictionarytuple của nó. Đương nhiên việc này là tùy ở bạn :D

Lời kết

Bạn có thể nhận thấy được namedtuple rất linh hoạt và có thể ứng dụng rất nhiều trường hợp. Một số sách nâng cao của Python như Fluent Python, Python Cookbook hoặc là một cuốn sách khác là Learning Python 5th Edition đều có nhắc đến.

Những nội dung trên đây được mình tham khảo từ

Cám ơn các bạn đã đọc.

Nhận xét

  1. ông viết blog từ tận 2017 cơ à không biết giờ ô ra sao rồi tôi đang trên con đường học python rất vui khi đc kết bạn đây là blog của tôi https://hauvietblog.blogspot.com/

    Trả lờiXóa
  2. Borgata Hotel Casino & Spa Announces Plans for Retail
    Borgata Hotel 안산 출장마사지 Casino & Spa 논산 출장안마 (formerly Harrah's Atlantic City) has been awarded the Hard 동두천 출장안마 Rock Hotel 당진 출장마사지 & Casino's Hard Rock Hotel & 울산광역 출장샵 Casino®

    Trả lờiXóa

Đăng nhận xét

Popular Posts

Tải nhạc từ mp3.zing.vn bằng Python (Download file.mp3 from mp3.zing.vn by using Python)