---
tags: Python
---
# Underscore( _ ) of Python
[TOC]
The underscore (_) is special in Python.
## Cases for using the underscore
### For storing the value of last expression in interpreter.
The python interpreter stores **the last expression value** to the special variable called ‘_’.
```python
>>> 10
10
>>> _
10
>>> _ * 3
30
>>> _
30
```
如果給值了,這個功能就失效。
```python
>>> _ = 3
>>> 10
10
>>> _
3
```
### For ignoring the specific values. (so-called “I don’t care”)
```python
# Ignore a value when unpacking
x, _, y = (1, 2, 3) # x = 1, y = 3
# Ignore the multiple values. It is called "Extended Unpacking" which is available in only Python 3.x
x, *_, y = (1, 2, 3, 4, 5) # x = 1, y = 5
# Ignore the index
for _ in range(10):
do_something()
# Ignore a value of specific location
for _, val in list_of_tuple:
do_something()
```
當然你也可以不用 `_` ,也可以達到一樣的效果。
### To give special meanings and functions to name of vartiables or functions.
[PEP8](https://pep8.org/#descriptive-naming-styles) 介紹了四種特別的命名格式。
#### `_single_leading_underscore`
weak “internal use” indicator.
表示內部使用。當外部 `from M import *` 時不會被包含在內。
> “Private” instance variables that cannot be accessed except from inside an object don’t exist in Python. However, there is a convention that is followed by most Python code: a name prefixed with an underscore (e.g. _spam) should be treated as a non-public part of the API (whether it is a function, a method or a data member).
當然 Python 不支援真的 private ,所以還是可以直接呼叫。
```python
import M
M._func()
```
1. 並不是 Private variable
2. 不需要 docstrings `lint: D103: Missing docstring in public function`
#### `single_trailing_underscore_`
避免和 Python built-in keywords 衝突。
```python
Tkinter.Toplevel(master, class_='ClassName')
```
但這種命名其實不夠精確,可以考慮更好的選擇,例如: `level_class` 。
#### `__double_leading_underscore`
```python
class A:
def _single_method(self):
pass
def __double_method(self): # for mangling
pass
class B(A):
def __double_method(self): # for mangling
pass
>>> import M
>>> dir(M.A)
['_A__double_method', '__doc__', '__module__', '_single_method']
>>> dir(M.B)
['_A__double_method', '_B__double_method', '__doc__', '__module__', '_single_method']
```
這種命名方法會 trigger 所謂的 name mangling ,避免產生命名碰撞,因為這樣可能會導致被繼承的父類裡面定義的其他 method 運作不正常。
[舉個例](https://aji.tw/python%E4%BD%A0%E5%88%B0%E5%BA%95%E6%98%AF%E5%9C%A8__%E5%BA%95%E7%B7%9A__%E4%BB%80%E9%BA%BC%E5%95%A6/):
我有一個好朋友,叫做 `Jason` :man:,他長的像這樣:
```python
class Jason:
location = 'HsinChu'
hobby = 'sleeping'
__wife = 'Mary'
def profile(self):
"""Print my personal profile."""
print(f'''
I live in {self.location}
My hobby is {self.hobby}
My wife is {self.__wife}
''')
```
> [PEP498 Literal String Interpolation](https://www.python.org/dev/peps/pep-0498/) f-string 是 Python3.6 引入的新方法。
> 相較於 `format` 更簡潔:
>
> ```python
> 'Hello, {name}. You are {age}.'.format(name=name, age=age)
> ```
>
> ```python
> f'Hello, {name}. You are {age}.'
> ```
>
> 效能也更高,比 format 快了一倍:F-strings provide a way to embed expressions inside string literals, using a minimal syntax. It should be noted that an f-string is really an expression evaluated at run time, not a constant value. In Python source code, an f-string is a literal string, prefixed with 'f', which contains expressions inside braces. The expressions are replaced with their values.
>
> pylint 需要升級到 2.x ,否則會被視為 `syntax-error` 。
> expression 內變數未定義時, pylint 能夠正確抓到錯誤:`undefined-variable` 。
我們來看看他的個人檔案會長什麼樣子:
```python
>>> Jason().profile()
I live in HsinChu
My hobby is sleeping
My wife is Mary
```
我是他的麻吉罵,而且跟他有很多共通點,所以我直接繼承他。不過我跟他住的地方不一樣,老婆也不一樣。
```
class Aji(Jason):
location = 'Taipei'
__wife = 'Boa'
```
那來看看我的個人檔案會長什麼樣子:
```python
>>> Aji().profile()
I live in Taipei
My hobby is sleeping
My wife is Mary
```
等等,我的老婆是 Boa 不是 Mary 啊!朋友妻不可戲啊 :scream:!
另外,別人的老婆也不是隨隨便便可以得的。
```python
>>> jason = Jason()
>>> jason.location
HsinChu
>>> jason.__wife
AttributeError: 'Jason' object has no attribute '__wife'
```
不過透過特殊的方法,~~還是可以取得 Jason 的老婆的~~。
```python
>>> jason._Jason__wife
'Mary'
```
#### `__double_leading_and_trailing_underscore__`
> __double_leading_and_trailing_underscore__ : "magic" objects or attributes that live in user-controlled namespaces. E.g. __init__ , __import__ or __file__ . Never invent such names; only use them as documented.
Python 都叫你不要自己發明了,就饒過自己吧。
~~鼎鼎大名的 [SQLAlchemy](https://github.com/zzzeek/sqlalchemy) 用了一堆像是 `__tablename__`, `__table__`, `__mapper__` 等等的東西,還沒爆炸但不知道會不會爆炸。~~
### To use as ‘Internationalization(i18n)’ or ‘Localization(L10n)’ functions.
It is just convention, does not have any syntactic functions.
國際化應用程式是一種使軟體可以適應各種語言的一種開發過程,而不需要工程上的更動。
* **i18n internationalization 國際化**:18 意味著在 internationalization 這個單字中,i 和 n 之間有 18 個字母。當軟體被移植到不同的語言及地區時,軟體本身不用做內部工程上的改變或修正。
* **L10n localization 在地化**:使用大寫的 L 以利區分 i18n 中的 i 和易於分辨小寫 l 與 1 。當移植軟體時,加上與特定區域設定有關的資訊和翻譯檔案的過程。
```python
# see official docs : https://docs.python.org/3/library/gettext.html
import gettext
gettext.bindtextdomain('myapplication','/path/to/my/language/directory')
gettext.textdomain('myapplication')
_ = gettext.gettext
# ...
print(_('This is a translatable string.'))
```
如果用這個方法然後還用到 ignoring the specific value 的功能,比較多的人會使用 `__` 雙底線來代表 ignore 。
~~這邊實際法我還沒看~~
### To separate the digits of number literal value.
增加可讀性 :thumbsup: 。
```python
dec_base = 1_000_000
bin_base = 0b_1111_0000
hex_base = 0x_1234_abcd
print(dec_base) # 1000000
print(bin_base) # 240
print(hex_base) # 305441741
```
## 資料來源
1. [Understanding the underscore( _ ) of Pythontra](https://medium.com/hackernoon/understanding-the-underscore-of-python-309d1a029edc)
2. [Python,你到底是在__底線__什麼啦!](https://aji.tw/python%E4%BD%A0%E5%88%B0%E5%BA%95%E6%98%AF%E5%9C%A8__%E5%BA%95%E7%B7%9A__%E4%BB%80%E9%BA%BC%E5%95%A6/)
3. [Python 3's f-Strings: An Improved String Formatting Syntax (Guide)](https://realpython.com/python-f-strings/)