Set and dict study notes in Python

1. Map type

dictIt is a maptype. Let's look at an example

a={
    
    }
print(isinstance(a,MutableMapping)) #True

# print(isinstance(dict,MutableMapping)) # False 因为isinstance判断的是实例的类型

Supplement: The dictionary type is aactually not to inherit the MutableMappingclass, but to implement MutableMappingsome methods (magic functions) in the class. The source code is finally realized through the MutableMapping.register(dict)statement, that dictis, the MutableMappingtype 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 collectionsthe abcmodule in the abstract base class of the source code , you can see that there are Mappingtypes and MutableMappingtypes (modifiable), but dictthey belong MutableMapping.

In MutableMappingthe definition of the class in a number of ways, such as __setitem__, __delitem__, popetc., MutableMappingclass inheritance is the Mappingclass.

listIt dictis the same as there are many operations, because they all inherit Collectionclasses.

2. Common methods in dict (only a few are quite important)

  • clearMethod (empty dictionary)
a = {
    
    "bobby1":{
    
    "company":"imooc"},
     "bobby2": {
    
    "company": "imooc2"}
     }
a.clear() 
print(a) # {}
  • copyMethod (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 acopied new_dict, because athe bobby1point in is also a dictionary {'company': 'im'}, this dictionary will not be copied anymore, so new_dictafter modification, it bobby1will still point to that dictionary, but the content of this dictionary has been modified. So the printed dictionary ahas changed. This is the mechanism of shallow copy.

Deep copy requires pythonthe copypackage 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, awas not affected.

  • Static method fromkeys(receive any iterableobject)

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.

  • getmethod

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'}
  • itemmethod

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'}
  • setfeaultmethod

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'}
  • updatemethod

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 iterableobject 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 Listand Dict.

Give a chestnut

Define a Mydictclass, let it inherit the dictclass, and then overwrite (overwrite) dictthe __setitem__method in the class , let it call dictthe __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"]=1this 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 inheritcollectionUserDictUserDict , 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

UserDictThere is a __missing__method in the source code class (such as the code below), and the method dictcan be overridden in ours __missing__.

This method is keycalled when we can't find a certain one . The logic is probably to judge keywhether it is in the datamiddle. If it is, it will directly return datathe value inside. If it is not, it will judge whether classthere 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 defaultdictclass 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_factoryis 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)
# {} 

setdefaultAnd defaultdictyou 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 frozensetcan 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的存储顺序和元素添加顺序有关

Guess you like

Origin blog.csdn.net/weixin_43901214/article/details/107027638