Python: các hàm tiện ích để thao tác với list, tuple và dict
- Details
Hồi còn làm việc với CakePHP, mình rất ấn tượng với class [Hash](https://book.cakephp.org/2.0/ja/core-utility-libraries/hash.html) của nó. Gần đây khi chuyển sang project dùng Python, nhiều khi thao tác với list, tuple và dict của Python lại thấy nhớ vài function trong class Hash của CakePHP. Vậy là quyết định clone lại 2 function sử dụng nhiều nhất là `Hash::get` và `Hash::insert` của CakePHP chuyển sang Python. Tất nhiên do đặc thù của list, tuple và dict trong Python check type nghiêm ngặt hơn trong PHP nên chưa thể clone được 100% chức năng của `Hash::get` và `Hash::insert` sang Python. Tuy nhiên code hiện tại vẫn phục vụ được yêu cầu cơ bản.
Source code được post ở dưới cuối. Ở đây sẽ ghi vài sample về cách sử dụng 2 hàm này.
### Cách dùng:
#### hash.get():
~~~ python
import hash
aDict = {
'a': {
'b': [0, 1, {'c': 'foo'}],
'd': {'e': 'bar'},
}
}
print hash.get(aDict, 'a.b') # => [0, 1, {'c': 'foo'}]
print hash.get(aDict, 'a.b.0') # => 0
print hash.get(aDict, 'a.b.2.c') # => 'foo'
print hash.get(aDict, 'a.d.e') # => 'bar'
print hash.get(aDict, 'f') # => None
~~~
#### hash.insert():
~~~ python
import hash
aDict = {
'a': {
'b': [0, 1, 2],
'c': {'d': 'foo'},
}
}
print hash.insert(aDict, 'a.e', 'Hello')
# 'a': {
# 'b': [0, 1, 2],
# 'c': {'d': 'foo'},
# 'e': 'Hello'
# }
print hash.insert(aDict, 'a.b', 'Hello')
# 'a': {
# 'b': [0, 1, 2, 'Hello'],
# 'c': {'d': 'foo'}
# }
print hash.insert(aDict, 'a.c', {'e': 'Hello'})
# 'a': {
# 'b': [0, 1, 2],
# 'c': {'d': 'foo', 'e': 'Hello'}
# }
print hash.insert(aDict, 'a.c', 'Hello')
# 'a': {
# 'b': [0, 1, 2],
# 'c': 'Hello'
# }
print hash.insert(aDict, 'e.f', 'None')
# 'a': {
# 'b': [0, 1, 2],
# 'c': {'d': 'foo'}
# },
# 'e': {
# 'f': None
# }
~~~
> ※ Chú ý: Parameter `aDict` sẽ bị thay đổi khi sử dụng `hash.insert`. Nếu không muốn làm thay đổi `aDict` thì cần copy `aDict` trước khi truyền vào `hash.insert`.
### Source code:
~~~ python
# coding: utf-8
#
# hash.py
#
# Utility functions for handling dict, list, tuple variable
#
# @author NVB
# @copyright 2017 NVB
# @license MIT
#
def get(arr, path):
''' Get value of item provided in path from a list, tuple or dict. '''
if isinstance(path, list):
parts = path
elif isinstance(path, str):
parts = path.split('.')
else:
raise TypeError('type of path must be str or dict.')
part = parts.pop(0)
if isinstance(arr, (list, tuple)):
try:
part = int(part)
except ValueError:
return None
if part > len(arr) - 1 or part < -len(arr):
return None
elif isinstance(arr, dict):
if part not in arr:
return None
else:
return None
if len(parts) > 0:
return get(arr[part], parts)
else:
return arr[part]
def insert(aDict, path, val):
''' Insert val into aDict follow by path. '''
if not isinstance(aDict, dict):
raise TypeError('type of item provided in path must be dict: %s.' % path)
if isinstance(path, list):
parts = path
elif isinstance(path, str):
parts = path.split('.')
else:
raise TypeError('type of path must be str or dict.')
part = parts.pop(0)
if len(parts) > 0:
if part not in aDict:
aDict[part] = {}
if isinstance(aDict[part], dict):
aDict[part].update(insert(aDict[part], parts, val))
else:
aDict[part] = insert(aDict[part], parts, val)
else:
if part not in aDict:
aDict[part] = val
elif isinstance(aDict[part], list):
aDict[part].append(val)
elif isinstance(aDict[part], dict) and isinstance(val, dict):
aDict[part].update(val)
else:
aDict[part] = val
return aDict
~~~