01/10/2018, 11:15

Hỏi về khai báo định danh (identifier) trong Python kiểu _a __a hay __a__

Xin chào mọi người! Em mới học Python. Mọi người cho em hỏi là khi định danh trong Python mà mình sử dụng gạch dưới kiểu _a __a hay __a__ thì nó có ý nghĩa gì? Có gì khác nhau? Cái này là để người đọc code hiểu hay để chương trình nhận biết ạ? Nó có phải gần giống Access Modifier trong Java không ạ? Em xin cảm ơn!

Henry viết 13:20 ngày 01/10/2018

Đầu tiên mình sẽ nói về một cái dấu _. Đây là một biến đặc biệt trong Python có vai trò giữ giá trị vừa mới được tính toán, được ghi rất rõ trên docs của Python khi bạn đọc tới mấy cái phần liên quan đến số. Ví dụ

>>> 3 * 5
15
>>> _
15
>>> 1 + 2
3
>>>  _
3
>>> 4 - 2
2
>>> _ + 2
4
>>> 'abc'  # bất cứ giá trị nào, không hẳn cứ phải là số
'abc'
>>> _
'abc'

Lưu ý: Khi chưa có cái giá trị gì, thì biến _ chưa được khởi tạo đâu.
Thế nên, đôi lúc người ta dùng biến với tên _ để lấp vô chỗ trống để không có lỗi đồng thời coi như giá trị rác. Ví dụ

>>> col = {'name': 'abc', 'age': 'xyz'} # bạn chỉ muốn lấy value
>>> for _, value in col.items():
...     print(value)
...

Còn trường hợp biến, class, method mà bắt đầu bằng _ sẽ được coi là private. Ví dụ

# file test.py
_name = 'name'
class _a: pass
age = 'age'
class b: pass

Thì lúc bạn import như sau

>>> from test import *
>>> _name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_name' is not defined
>>> age
'age'
>>> _a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_a' is not defined

Lưu ý: Khi bạn import theo kiểu này thì không phải private nhé

>>> import test
>>> test._name  # ok
'name'

Còn với trường hợp nó có dấu _ ở cuối cùng, thường là tránh các keyword có sẵn như

>>> class_ = 'class'
>>> list_ = 'list'

Nếu tên thuộc tính của class bắt đầu bằng 2 dấu __ thì nó là private ngay trong đó luôn

>>> class a:
...     __name = 'name'
...
>>> a.__name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'a' has no attribute '__name'
>>> b = a()
>>> b.__name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'a' has no attribute '__name'

Trường hợp nữa là nó được bắt đầu bằng __ 2 dấu, và kết thúc cũng __ là special attribute. Một vài ví dụ

def __init__(self):
    pass
def __eq__(self, value):
    pass
def __getitem__(self, idx):
    pass
__file__ # lưu giá trị là tên của file python được thực thi.

Một trường hợp khác đó là dùng _ để làm cho số dễ đọc hơn.

>>> n = 1_234_567  # tương đương với 1234567
>>> n  # nhưng lúc trình bày code sẽ dễ đọc, không nhầm lần
1234567
>>> 1_000_000_000 # đặc biệt là khi có nhiều số 0
1000000000

Cũng có thể dùng cách này để convert bin, hex

>>> 0b_10  # 10 là 2 trong hệ nhị phân
2
>>> 0b_1010_1011 # 10101011 là 171
171
>>> 0x_1234_abcd # hex nữa
305441741

Còn với bình thường, tên biến, tên hàm được đặt theo kiểu abc_xyz_mnp theo chuẩn PEP8
Mình biết tới vậy thôi

Nguyễn Văn Hùng viết 13:25 ngày 01/10/2018

Cảm ơn anh! Rất chi tiết và có cả ví dụ dễ hiểu.

Bài liên quan
0