Skip to content

Commit

Permalink
1.2
Browse files Browse the repository at this point in the history
1.The unique value (the global variable `unique`) no longer pursue individuality, but adopt a safe generic scheme.
2.Optimized `MasqueradeClass`, including optimization of exception output, optimization of equality judgment method, and solved the problem that cannot `copy` and `deepcopy` correctly after masquerading hash value.
3.Optimized the `gdict` core (initialization process), including optimizing the data merge scheme, changing the data decomposition scheme (using the original type of data), and no longer shredding iterators.
4.Fixed an issue in `update` that could cause data clutter.
5.The methods `deepget` and `deepset` support manipulating the built-in `dict` instances, and are therefore about to remove the methods `getdeep` and `setdeep`, using the former uniformly.
6.Optimized methods `copy`, `deepget`, `deepset`, `deepsetdefault`.
7.Parameter annotation and standardization greatly optimized.

1.唯一值(全局变量 `unique`)不再追求个性,而是采用稳妥的通用方案。
2.优化了 `MasqueradeClass`,包括优化了异常输出,优化了相等性判断方法,并解决了伪装哈希值后无法正确 `copy` 和 `deepcopy` 的问题。
3.优化了 `gdict` 核心(初始化过程),包括优化了数据合并方案,改变数据分解方案(使用数据的原始类型),并不再分解迭代器。
4.修复了 `update` 中可能导致数据混乱的问题。
5.方法 `deepget` 和 `deepset` 支持操作内置 `dict` 实例,并因此即将移除方法 `getdeep` 和 `setdeep`,统一使用前者。
6.优化方法 `copy`, `deepget`, `deepset`, `deepsetdefault`。
7.参数注解及规范性大幅优化。
  • Loading branch information
2018-11-27 committed Apr 22, 2023
1 parent 544631c commit c693f84
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 305 deletions.
3 changes: 2 additions & 1 deletion NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ Copyright (c) 2022, 2023 GQYLPY <http://gqylpy.com>. All rights reserved.
gqylpy-dict is released under the dual license WTFPL and Apache-2.0.

────────────────────────────────────────────────────────────────────────────────
Lines 48-93 in the "gqylpy_dict/g dict.py" file are licensed under Apache-2.0:

Lines 51-95 in the "gqylpy_dict/g dict.py" file are licensed under Apache-2.0:

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
256 changes: 106 additions & 150 deletions gqylpy_dict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
>>> x.deepget('a[0].b')
'B'
@version: 1.1.4
@version: 1.2
@author: 竹永康 <gqylpy@outlook.com>
@source: https://github.com/gqylpy/gqylpy-dict
Expand All @@ -42,42 +42,42 @@
0. You just DO WHAT THE FUCK YOU WANT TO.
"""
from typing import Optional, Iterator, Union, Any
from typing import Optional, Union, Tuple, List, Hashable, Any


class GqylpyDict(dict):
class gdict(dict):

def __new__(cls, __data__={}, /, **kw):
if __data__.__class__ is dict:
return dict.__new__(cls)
def __new__(cls, __data__={}, /, **data):
if isinstance(__data__, dict):
return __data__ if __data__.__class__ is cls else dict.__new__(cls)

if isinstance(__data__, (list, tuple, set, frozenset, Iterator)):
return [cls(v) for v in __data__]
if isinstance(__data__, (list, tuple, set, frozenset)):
return __data__.__class__(cls(v) for v in __data__)

return __data__

def __init__(self, __data__=None, /, **kw):
if __data__.__class__ is dict:
kw and __data__.update(kw)
def __init__(self, __data__=None, /, **data):
if __data__ is None:
__data__ = data
else:
__data__ = kw
__data__.update(data)

for name, value in __data__.items():
self[name] = GqylpyDict(value)
for key, value in __data__.items():
dict.__setitem__(self, key, gdict(value))

def __getattr__(self, key: str) -> Any:
def __getattr__(self, key: str, /) -> Any:
return self[key]

def __setattr__(self, key: str, value: Any) -> None:
def __setattr__(self, key: str, value: Any, /) -> None:
self[key] = value

def __delattr__(self, key: str) -> None:
def __delattr__(self, key: str, /) -> None:
del self[key]

def __setitem__(self, key: str, value: Any) -> None:
dict.__setitem__(self, key, GqylpyDict(value))
def __setitem__(self, key: Hashable, value: Any, /) -> None:
dict.__setitem__(self, key, gdict(value))

def __hash__(self):
def __hash__(self) -> int:
"""
The first thing you have to understand is that the built-in dict object
is unhashable. Don't be misled!
Expand All @@ -90,177 +90,133 @@ def __hash__(self):
"""
return -2

def copy(self) -> 'gdict':
"""Get a replica instance."""

def deepget(
self,
keypath: str,
deepkey: str,
/,
default: Optional[Any] = None,
default: Optional[Any] = None,
*,
ignore: Union[list, tuple] = None
ignore: Optional[Union[Tuple[Any], List[Any]]] = None
) -> Any:
"""
@param keypath: Hierarchy keys, use "." connection.
@param default: Default return value if the keypath does not found.
@param ignore: Use a list or tuple to specify one or more undesired
return values. If the return value is undesired, it is
ignored and the default value is returned.
>>> d = gdict({'a': [{'b': 'B'}]})
>>> d.deepget('a[0].b')
Try to get a depth value, if not then return the default value.
>>> x = gdict({'a': [{'b': 'B'}]})
>>> x.deepget('a[0].b')
'B'
>>> d.deepget('a[0].c', 'C')
'C'
@param deepkey
Hierarchical keys, use "." join, if the next layer is an array then
use the index number to join.
@param default
If not get the depth value then return the default value.
@param ignore
Use tuple or list to specify one or more undesired values, if the
depth value is in it then return the default value. This parameter
may be removed in the future.
"""

def deepset(self, keypath: str, value: Any) -> None:
def deepset(self, deepkey: str, value: Any) -> None:
"""
@param keypath: Hierarchy keys, use "." connection.
@param value: Will set in self, according to keypath.
Set a depth value (to the depth key), overwrite if exists.
>>> d = gdict({'a': [{'b': 'B'}]})
>>> x = gdict()
>>> x.deepset('a[1].b', 'B')
>>> x
{'a': [None, {'b': 'B'}]}
>>> d.deepset('a[0].c', 'C')
>>> d
{'a': [{'b': 'B', 'c': 'C'}]}
@param deepkey
Hierarchical keys, use "." join, if the next layer is an array then
use the index number to join.
>>> d.deepset('d[1].f', 'F')
>>> d
{'a': [{'b': 'B', 'c': 'C'}], 'd': [None, {'f': 'F'}]}
@param value
Pass in any value, will be set to the value of the depth key,
overwrite if exists.
"""

def deepsetdefault(self, keypath: str, value: Any) -> Any:
def deepsetdefault(self, deepkey: str, default: Any) -> Any:
"""
@param keypath: Hierarchy keys, use "." connection.
@param value: Will set in self, if keypath not found.
If the depth key does not exist then set the default value and return
it, otherwise return the value of the depth key.
>>> d = gdict({'a': [{'b': 'B'}]})
>>> d.deepsetdefault('a[0].b', 'X')
>>> x = gdict()
>>> x.deepsetdefault('a[0].b', 'B')
'B'
>>> d.deepsetdefault('a[0].c', 'X')
'X'
>>> x
{'a': [{'b': 'B'}]}
@param deepkey
Hierarchical keys, use "." join, if the next layer is an array then
use the index number to join.
>>> d
{'a': [{'b': 'B', 'c': 'X'}]}
@param default
Pass in any value, will be set to the value of the depth key if the
depth key does not exist.
"""

def deepcontain(self, keypath: str, /) -> bool:
def deepcontain(self, deepkey: str, /) -> bool:
"""
@param keypath: Hierarchy keys, use "." connection.
Return True if the depth key exists else False.
>>> d = gdict({'a': [{'b': 'B'}]})
>>> d.deepcontain('a[0].b')
True
>>> d.deepcontain('a[0].c')
False
>>> x = gdict({'a': [{'b': 'B'}]})
>>> x.deepcontain('a[0].b')
True
>>> x.deepcontain('a[1].b')
False
@param deepkey
Hierarchical keys, use "." join, if the next layer is an array then
use the index number to join.
"""

@classmethod
def getdeep(
cls,
data: dict,
keypath: str,
default: Optional[Any] = None,
data: dict,
deepkey: str,
/,
default: Optional[Any] = None,
*,
ignore: Union[list, tuple] = None
ignore: Optional[Union[Tuple[Any], List[Any]]] = None
) -> Any:
"""
`getdeep` based on `deepget`, and is provided for built-in `dict`. If
you want to use `deepget` but don't want to or can't give up the
The `getdeep` based on `deepget`, and is provided for built-in `dict`.
If you want to use `deepget` but don't want to or can't give up the
original data, can use `getdeep`.
@param data: Expectation is a multilevel dict.
@param keypath: Hierarchy keys, use "." connection.
@param default: Default return value if the keypath does not found.
@param ignore: Use a list or tuple to specify one or more undesired
return values. If the return value is undesired, it is
ignored and the default value is returned.
>>> d = {'a': [{'b': 'B'}]}
>>> gdict.getdeep(d, 'a[0].b')
'B'
>>> gdict.getdeep(d, 'a[0].c', 'C')
'C'
"""
return cls.deepget(data, keypath, default, ignore=ignore)
warnings.warn(
f'will be deprecated soon, replaced to {cls.deepget}.',
DeprecationWarning
)
return cls.deepget(data, deepkey, default, ignore=ignore)

@classmethod
def setdeep(cls, data: dict, keypath: str, value: Any) -> None:
def setdeep(cls, data: dict, deepkey: str, value: Any) -> None:
"""
`setdeep` based on `deepset`, and is provided for built-in `dict`. If
you want to use `deepset` but don't want to or can't give up the
The `setdeep` based on `deepset`, and is provided for built-in `dict`.
If you want to use `deepset` but don't want to or can't give up the
original data, can use `setdeep`.
@param data: Expectation is a multilevel dict.
@param keypath: Hierarchy keys, use "." connection.
@param value: Will set in self, according to keypath.
>>> d = {'a': [{'b': 'B'}]}
>>> gdict.setdeep(d, 'a[0].c', 'C')
>>> d
{'a': [{'b': 'B', 'c': 'C'}]}
>>> gdict.setdeep(d, 'd[1].f', 'F')
>>> d
{'a': [{'b': 'B', 'c': 'C'}], 'd': [None, {'f': 'F'}]}
"""
cls.deepset(data, keypath, value)
warnings.warn(
f'will be deprecated soon, replaced to {cls.deepset}.',
DeprecationWarning
)
cls.deepset(data, deepkey, value)


class _xe6_xad_x8c_xe7_x90_xaa_xe6_x80_xa1_xe7_x8e_xb2_xe8_x90_x8d_xe4_xba_x91:
""" QYYYQLLYYYYYYYQLYYQYYQQQYQQYQQQQQQQQQQQQQQQQQQQQQQYYYQQQQQQYL
YYYYQYLLQYLLYYQYYYYYYYQQYQYQYQQQQQQQQQQQQQQQQQQQQQQQYYYQQQQQQ
QYYYYLPQYLPLYYYLLYYYYYYYYQQQYQQQQQQQQQQQQQQQQQQQQQQQYYYYQQQQQP
QYYQLPLQYLLYYQPLLLYYYYYYQYYQYQQQQQQQQQQQQQQYQQQQQQQQYYQYQQQQQQP
QYYQYLLYYYLLYQYLLYYYYYYYYQYYQYQYYYQQQQQQQQQQYQQQQQQYQQYQYYQQQQQYP
LQYQYYYYQYYYYYQYYYYYYYYYYYYYYYQQYYYYYYYYYQQQQYQQQQQQYQQYQYYQQQQQQ P
QYQQYYYYQYYYQQQYYYYYYYYQYQYYYYQQYYYQYQYYQQQQYQQQQQQQYQQYQYYQQQQQQ P
QYQQYYYYQYYYQQQYYYYYYYYQYQYYYYYQYYYYQYYYQQQQYQQQQQQQYQQYQQYQQQQYYP
QYQYYYYYQYYYQQQ PYLLLYP PLYYYYYYQYYYYYYQQQQYYQQQQQQYQQYQQQYQQQQYQ
PQQYYYYYQYYQQYQQQQQQQQQQYP PPLYQYQYQYQLQQQQQYQQYQQQYYQQQYY
QQYYYYYQQYQLYQQPQQQQQL QYL PPYYLYYLQYQQYYQYQQQQYYQPQYL
YQYYYYQQQYQ LYLQQQQQQYQQ YQQQQQGQQQQQQYQYYQQQQYQPQYQ P
L QYYYYQQLYQ Y YPYQQQQQ LQQQQQL YQQQQYQQYQYQQYYQQYQP P
YYQYYQQ Q LQQQQQQY YQYQQQQQQYYQYLQYQQYQQYYQYQL P
Y LYQLQQPL Y P P QLLQQQQQ Q PQQQQYQQYYQQL P
P PYQYQQQQPQ PQQQQQQY QQYQYYQQYYQPP
L QQQYQ YYYY PQ L P LPQYQYYQQLQ P
Y PPQQYYL LYQL PQLQYQQYQYQ L
Y QQYQPP PYQY PQ Q QQYQYQYL L
Y QQYYQ L QYQP PLLLLLYL LQQ LQYYQQQP P L
L PPLQYYQ Y LQQQ LQYQ QYYYQQ P
L Q QYQ Y QQPYL PQYYYYPPQYYQQQP L
L L PQQL LYQ PQP QL PYYYPLQLYQ QY P Y
P P PQQP QY QLLQQP LYYLQ PQYPQQQP P QY P L
PYQYYY PQ PQ L Q P L
PQYLYYYPQ PLPL L QY YQYYQYLYQQQ P
PYLLLLLYYYQ P L P PYL PQYYLLLLLLLQ
LYPLLLLLLYYYY Y YQY LLLPPY LYYYLLLLLLLLY
YLLLYLLLLLLYYQ Q PQ YYYLLLLLLLLLLYP
YLLLLLLLLLLLLLLYQQ PYYQYYLLLLLLLLYYYLQ
QLLLLLLLLLLLLLLLLLYYQYP YQYYLLLLLLLLLLLLLLLQ
YLLLLLLLLLLLLLLLLLLLYYYLLYYYLLLLLLLLLLLLLLLLLLLLLLYP
PLLLLLLLLLLLLLLLLLLLLLLLYLLLLLLLLLLLLLLLLLLLLLLLYLYLL
LLLLLLLLLLYYLLLLLLYLLLLLLLLLLLLLLLL GQYLPY LLLYLYLLLY
QLLLLYYLYLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLQYYYYLLQ
QLLLLLYYQYLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLQLYYLLLQ
LYLLYLLLQYYLLLLLLLLLLLLLLLLLLLLLLLLLLLLLYLLLLLQYYYYYLYQ
YLLLYYLLYQYLLLLLLLLLLLLLLLLLLLLLLLLLLLLYLLLLLYYYYQLLLLY
QLLLYYYYYQLLLLLLLLLLLLLLYLLLLLLLLLLLLLLLLLLLLYYYLQLLPLLQ
YLYLLQYYYQLLLLLLLLLLLLLLLLLLLLLLLLLLLLYYLLLLLYYQYYLLLLLQ
LYLLLLLYYYQLLYLLLLLLLLLLLLYLYLLYYLLLLYLLLLLLLYYYQQLLLLLLLY
YLLLLLLYYYQLLYLLLLLLLYLYLLLLLLLLLLLLLLLLLLLLYYYYQQLYLLLLLQ
QLLLYLLLQYQLQLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLYYYQYYLLLLLLLY
QLLLLLLLLQQYQLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLQYYQYYLLLLLLLQ
QLLLLLLLLLQQYLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLYYYYLLLLLLLLLYL
QLLLLYLYYLYQLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLQYYYLLLLLLLLLQ
YLLLLLLLYYLQLLLLLLLLLLLLLLLLLLLLLLLLLYLLLLLLLLYQYYLLLLLLLLLQ
QLLLLLYLYYYYLLLLLPLLLLLLLYLYLLLLLLLLLLLLLLLLLLLQYYLLLLLLLLYP
YYLYYLLYYYQLLLLLLLLYLLLLLLLLLLLLLLLLLLLLLLYLYLLYQYYLLLLLLYL
QLLLLLLYQYLLLLLLLLLLLLLLLLLLLLLYYLYLLLLLLLLLLLYQQQQQQQLYL """
import sys

__import__(f'{__name__}.g {__name__[7:]}')
globals()['GqylpyDict'] = globals()[f'g {__name__[7:]}'].GqylpyDict
gdict = globals()[f'g {__name__[7:]}'].GqylpyDict

for gname in globals():
if gname[0] == '_' and gname != '__name__':
setattr(gdict, gname, globals()[gname])

gdict = GqylpyDict
sys.modules[__name__] = gdict.gdict = gdict
Loading

0 comments on commit c693f84

Please sign in to comment.