Article Directory
1. Map type
dict
It is a map
type. Let's look at an example
a={
}
print(isinstance(a,MutableMapping)) #True
# print(isinstance(dict,MutableMapping)) # False 因为isinstance判断的是实例的类型
Supplement: The dictionary type is a
actually not to inherit the MutableMapping
class, but to implement MutableMapping
some methods (magic functions) in the class. The source code is finally realized through the MutableMapping.register(dict)
statement, that dict
is, the MutableMapping
type can be judged after registration
Specifically
from abc import ABCMeta, abstractmethod
import sys
__all__ = ["Awaitable", "Coroutine",
"AsyncIterable", "AsyncIterator", "AsyncGenerator",
"Hashable", "Iterable", "Iterator", "Generator", "Reversible",
"Sized", "Container", "Callable", "Collection",
"Set", "MutableSet",
"Mapping", "MutableMapping",
"MappingView", "KeysView", "ItemsView", "ValuesView",
"Sequence", "MutableSequence",
"ByteString",
]
In collections
the abc
module in the abstract base class of the source code , you can see that there are Mapping
types and MutableMapping
types (modifiable), but dict
they belong MutableMapping
.
In MutableMapping
the definition of the class in a number of ways, such as __setitem__
, __delitem__
, pop
etc., MutableMapping
class inheritance is the Mapping
class.
list
It dict
is the same as there are many operations, because they all inherit Collection
classes.
2. Common methods in dict (only a few are quite important)
clear
Method (empty dictionary)
a = {
"bobby1":{
"company":"imooc"},
"bobby2": {
"company": "imooc2"}
}
a.clear()
print(a) # {}
copy
Method (shallow copy and deep copy)
What is a shallow copy, see the following example.
a = {
"bobby1": {
"company": "im"},
"bobby2": {
"company": "im2"}
}
print(a)
new_dict = a.copy()
new_dict["bobby1"]["company"] = "im3"
print(new_dict)
print(a)
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im3'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im3'}, 'bobby2': {'company': 'im2'}}
After the dictionary is a
copied new_dict
, because a
the bobby1
point in is also a dictionary {'company': 'im'}
, this dictionary will not be copied anymore, so new_dict
after modification, it bobby1
will still point to that dictionary, but the content of this dictionary has been modified. So the printed dictionary a
has changed. This is the mechanism of shallow copy.
Deep copy requires python
the copy
package in . Consider the following example:
import copy
a = {
"bobby1": {
"company": "im"},
"bobby2": {
"company": "im2"}
}
print(a)
new_dict = copy.deepcopy(a)
new_dict["bobby1"]["company"] = "im3"
print(new_dict)
print(a)
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im3'}, 'bobby2': {'company': 'im2'}}
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im2'}}
You can see the resulting modified copy of new_dict
, a
was not affected.
- Static method
fromkeys
(receive anyiterable
object)
Look directly at the example
new_list = ["bobby1", "bobby2"]
new_dict = dict.fromkeys(new_list, {
"company": "im"})
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
Use the elements in the list as keys and add values yourself.
get
method
The first parameter is the key to be obtained, and the second parameter defaults to the specified output if the key is not found in the dictionary.
# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
value = new_dict.get("bobby", {
"jj"})
print(value) # {"jj"}
# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
value = new_dict.get("bobby1")
print(value)
# {'company': 'im'}
item
method
See an example
# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
for key, value in new_dict.items():
print(key, value)
# bobby1 {'company': 'im'}
# bobby2 {'company': 'im'}
setfeault
method
Source code
def setdefault(self, *args, **kwargs): # real signature unknown
"""
Insert key with a value of default if key is not in the dictionary.
Return the value for key if key is in the dictionary, else default.
"""
pass
Look at the example (actually add key-value pairs)
# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
defult = new_dict.setdefault("bobby", "im2")
print(defult)
print(new_dict)
# im2
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}, 'bobby': 'im2'}
update
method
Source code
def update(self, E=None, **F): # known special case of dict.update
"""
D.update([E, ]**F) -> None. Update D from dict/iterable E and F.
If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]
If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v
In either case, this is followed by: for k in F: D[k] = F[k]
"""
pass
See an example
# new_dict : {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}}
new_dict.update({
"bobby": "im2"})
print(new_dict)
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}, 'bobby': 'im2'}
Of course, any iterable
object can be passed .
new_dict.update(bobby = "im4",bobby4="im5")
# new_dict.update([("bobby" , "im4"),("bobby4","im5")]) #列表也可以
# new_dict.update((("bobby" , "im4"),("bobby4","im5"))) #元组也可以
print(new_dict)
# {'bobby1': {'company': 'im'}, 'bobby2': {'company': 'im'}, 'bobby': 'im4', 'bobby4': 'im5'}
3. Subclasses of dict (UserDict and Defaultdict)
- It is not recommended to inherit
List
andDict
.
Give a chestnut
Define a Mydict
class, let it inherit the dict
class, and then overwrite (overwrite) dict
the __setitem__
method in the class , let it call dict
the __setitem__
method of the parent class , doubled value
.
class Mydict(dict):
def __setitem__(self,key,value):
super().__setitem__(key,value*2)
my_dict = Mydict(one=1)
print(my_dict) # {'one':1}
The output after instantiation is {'one':1}
that the __setitem__
magic function is not called .
But if we use my_dict["one"]=1
this method, we find that we will call the __setitem__
method, and the result becomes{'one':2}。
So in some cases, the C language implementation dict
(built-in type) will not call the overridden method. If you really want to inheritcollection
UserDict
UserDict
, you can use the module . That is to inherit .
from collections import UserDict
class Mydict(UserDict):
def __setitem__(self,key,value):
super().__setitem__(key,value*2)
my_dict = Mydict(one=1)
print(my_dict) # {'one':2}
defaultdict
Preface
UserDict
There is a __missing__
method in the source code class (such as the code below), and the method dict
can be overridden in ours __missing__
.
This method is key
called when we can't find a certain one . The logic is probably to judge key
whether it is in the data
middle. If it is, it will directly return data
the value inside. If it is not, it will judge whether class
there is a __missing__
magic function in this, and call it if it is. .
def __getitem__(self, key):
if key in self.data:
return self.data[key]
if hasattr(self.__class__, "__missing__"):
return self.__class__.__missing__(self, key)
raise KeyError(key)
The defaultdict
class actually rewrites the __missing__
method. From the if self.default_factory is None: raise KeyError((key,))
sum self[key] = value = self.default_factory()
statement in the method , if a key value is not found, it will set the value in, that is, call it default_factory()
.
def __missing__(self, key): # real signature unknown; restored from __doc__
"""
__missing__(key) # Called by __getitem__ for missing key; pseudo-code:
if self.default_factory is None: raise KeyError((key,))
self[key] = value = self.default_factory()
return value
"""
pass
But default_factory
is actually a property, a set value, the value assigned to Key ( self[key] = value = self.default_factory()
)
default_factory = property(lambda self: object(), lambda self, v: None, lambda self: None) # default
"""Factory for default value called by __missing__()."""
Give a chestnut
from collections import defaultdict
my_dict = defaultdict(dict) # 若为int 返回0;若为list 返回[]
my_value = my_dict["bobby"]
print(my_value)
# {}
setdefault
And defaultdict
you can also refer to this good article to understand- article address
4、set和frozenset
set collection fronzenset immutable collection
Disorder, not repeat
set
# b = set(['a', 'b', 'c', 'd', 'e'])
# print(b) # {'e', 'b', 'd', 'c', 'a'} 每次结果不一样,无序
s = set('abcdee')
# {'a', 'b', 'd', 'e', 'c'}
An initialization method
set={
'a','b'}
print(type(set)) # <class 'set'>
fronezset
s = {
'a', 'b'}
s.add('c')
print(s) #{'b','a','c'}
s = frozenset("abcde")
print(s) # frozenset({'e', 'c', 'd', 'a', 'b'})
# s.add('b') # AttributeError: 'frozenset' object has no attribute 'add'
Note: Immutable types frozenset
can be used as dictionarieskey
- Add data to set
s = {
'a', 'b'}
print(s)
another_set = set("cef")
s.update(another_set)
print(s)
# {'b', 'a'}
# {'b', 'e', 'f', 'a', 'c'}
difference
Subtraction
s = {
'a', 'b', 'c'}
print(s)
another_set = set("cef")
re_set = s.difference(another_set) # re_set = s - another_set 这样也是一样的效果,s中有,anot中没有
print(re_set)
# {'a', 'b'}
- Find elements in the collection (in)
if 'c' in re_set:
print('yes')
Supplement: As long as the object implements the __contains__
magic function, it can be used in
.
- Determine whether it is a subset
print(s.issubset(re_set)) #True
5. Supplementary knowledge
dict查找的性能远远大于list
在dict中查找元素不会随着dict的增大而增大
dict的key或者set的值都必须是可以hash的,不可变对象都是可hash的,比如str,fronzenset,tuple等或者自己实现的类 `__hash__`
dict的内存花销大,但是查询速度快,自定义的对象或者python内部的对象都是用dict包装的
dict的存储顺序和元素添加顺序有关