流畅的Python笔记

news2024/11/18 3:37:10

流畅的Python

  • 第一部分 序幕
    • 第 1 章 Python 数据模型
  • 第二部分 数据结构
    • 第 2 章 序列构成的数组
      • 列表推导
      • 生成器表达式
      • 元组
      • 切片
      • 对序列使用+和*
      • 序列的增量赋值
      • list.sort方法和内置函数sorted
      • bisect
      • 数组
      • memoryview
      • deque
    • 第 3 章 字典和集合
    • 第 4 章 文本和字节序列
  • 第三部分 把函数视作对象
    • 第 5 章 一等函数
    • 第 7 章 函数装饰器和闭包
      • 初探装饰器
      • 变量作用域规则
      • 闭包
      • nonlocal
      • 一个简单的装饰器,输出函数的运行时间
  • 第四部分 面向对象惯用法
    • 第 8 章 对象引用、可变性和垃圾回收
      • == 和 is
      • 元组的相对不可变性
      • 默认浅拷贝
      • 函数的参数作为引用时
    • 第 9 章 符合Python风格的对象
      • classmethod与staticmethod
  • 参考资料

第一部分 序幕

第 1 章 Python 数据模型

import collections
from random import choice

# 构建简单的类,类名:Card,属性:rank和suit
Card = collections.namedtuple('Card', ['rank', 'suit'])

# 背面有色情图片的扑克牌(来自百度翻译)
class FrenchDeck:
   ranks = [str(n) for n in range(2, 11)] + list('JQKA')
   suits = 'spades diamonds clubs hearts'.split()
   
   def __init__(self):
      self._cards = [Card(rank, suit) for suit in self.suits
                     for rank in self.ranks]
   
   def __len__(self):
      return len(self._cards)
   
   def __getitem__(self, position):
      return self._cards[position]
   
   def sort_strategy(self, card):
      suit_rank_map = dict(spades=3, hearts=2, diamonds=1, clubs=0)
      rank_idx = FrenchDeck.ranks.index(card.rank)
      return rank_idx * len(suit_rank_map) + suit_rank_map[card.suit]


if __name__ == '__main__':
   deck = FrenchDeck()
   print(len(deck))  # len调用的是__len__
   print(deck[-1])   # deck[-1]调用的是__getitem__
   print(choice(deck))  # 随机
   print(deck[:3])   # 取前三个deck[0],deck[1],deck[2]
   print(deck[12::13])   # 从第12开始,再每隔13取一个
   
   # 实现了__getitem__,FrenchDeck就可以迭代了,迭代背后调用了__iter__
   for card in deck:
      print(card)

   print("反向迭代")
   for card in reversed(deck):
      print(card)

   print("按照指定排序策略排序")
   for card in sorted(deck, key=deck.sort_strategy):
      print(card)

from math import hypot


class Vector:
   def __init__(self, x=0, y=0):
      self.x = x
      self.y = y

   def __repr__(self):
      return 'Vector(%r, %r)' % (self.x, self.y)

   def __abs__(self):
      return hypot(self.x, self.y)

   def __bool__(self):
      return bool(self.x or self.y)

   def __add__(self, other):
      x = self.x + other.x
      y = self.y + other.y
      return Vector(x, y)

   def __mul__(self, scalar):
      return Vector(self.x * scalar, self.y * scalar)

if __name__ == '__main__':
   v1 = Vector(1, 2)
   v2 = Vector(3, 4)
   print(v1)   # 调用__repr__或__str__;若无,打印类似<__main__.Vector object at 0x1025e4070>
   print(str(v1)) # 调用__repr__或__str__;若无,打印类似<__main__.Vector object at 0x1025e4070>
   print(v1 + v2) # 调用__add__
   print(v1 * 2)  # 调用__mul__
   print(abs(v2)) # 调用__abs__
   print(bool(v1))   # 默认自己定义类的实例是True,若有__bool__、__len__,就逐次调用即判即返回
   
  • 特殊方法
    https://docs.python.org/3/reference/datamodel.html

  • 为什么len不是普通方法?
    如果x是内置类型实例,len(x) 的速度非常快(CPython直接从C结构体里读取对象的长度)

  • 推荐书籍
    《Python 技术手册》
    《Python 参考手册》
    《Python Cookbook》

第二部分 数据结构

第 2 章 序列构成的数组

Python 标准库用 C 实现了丰富的序列类型,列举如下。

  • 容器序列
    list、tuple 和 collections.deque,这些序列能存放不同类型的数据。

  • 扁平序列
    str、bytes、bytearray、memoryview 和 array.array,这类序列只能容纳一种类型。

  • 可变序列
    list、bytearray、array.array、collections.deque 和 memoryview。

  • 不可变序列
    tuple、str 和 bytes。

列表推导

# 把一个字符串变成 Unicode 码位的列表

symbols = '$¢£¥€¤'

# 方式一
codes = []
for symbol in symbols:
	codes.append(ord(symbol))

# 方式二(列表推导)
codes = [ord(symbol) for symbol in symbols]
# Python 2.x 和 Python 3.x 列表推导式里的变量作用域对比

Python 2.7.18 (default, Oct  2 2021, 04:20:38)
[GCC Apple LLVM 13.0.0 (clang-1300.0.29.1) [+internal-os, ptrauth-isa=deploymen on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 1
>>> abc = [x for x in 'abc']
>>> x	# python 2.x,会被列表推导里的同名变量的值取代
'c'
>>> abc
['a', 'b', 'c']


Python 3.8.9 (default, Oct 26 2021, 07:25:53)
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x = 1
>>> abc = [x for x in 'abc']	# x 在列表推导的局部作用域
>>> x	# python 3.x,不会被列表推导里的同名变量的值取代
1
>>> abc
['a', 'b', 'c']
# 列表推导式与map/filter对比

>>> symbols = '$¢£¥€¤'
>>> beyond_ascii = [ord(s) for s in symbols if ord(s) > 127]
>>> beyond_ascii
[162, 163, 165, 8364, 164]
>>>
>>> beyond_ascii = list(filter(lambda c: c > 127, map(ord, symbols)))
>>> beyond_ascii
[162, 163, 165, 8364, 164]
# 列表推导计算笛卡儿积

>>> colors = ['black', 'white']
>>> sizes = ['S', 'M', 'L']
>>> tshirts = [(color, size) for color in colors for size in sizes]
>>> tshirts
[('black', 'S'), ('black', 'M'), ('black', 'L'), ('white', 'S'), ('white', 'M'), ('white', 'L')]

生成器表达式

# 用生成器表达式初始化元组和数组

>>> symbols = '$¢£¥€¤'
>>> tuple(ord(symbol) for symbol in symbols)
(36, 162, 163, 165, 8364, 164)

>>> import array
>>> array.array('I', (ord(symbol) for symbol in symbols))
array('I', [36, 162, 163, 165, 8364, 164])
# 使用生成器表达式计算笛卡儿积

>>> colors = ['black', 'white']
>>> sizes = ['S', 'M', 'L']
>>> for tshirt in ('%s %s' % (c, s) for c in colors for s in sizes):
...     print(tshirt)
...
black S
black M
black L
white S
white M
white L

元组

>>> coordinates = (1, 2)
>>> city, year = ('Shanghai', 2001)
>>> city_year_list = [('Shanghai', 2001), ('Beijing', 1999)]
>>> for city_year in city_year_list:
...     print('%s-%d' % city_year)	# 元组拆包
...
Shanghai-2001
Beijing-1999
>>>
>>> for city, _ in city_year_list:
...     print(city)
...
Shanghai
Beijing
>>> import os
>>> ret = os.path.split('/home/luciano/.ssh/idrsa.pub')
>>> ret
('/home/luciano/.ssh', 'idrsa.pub')
# 元组拆包

>>> coordinates = (1, 2)
>>> coordinates[0]
1
>>> coordinates[1]
2
>>> x, y = coordinates	# 元祖拆包
>>> x
1
>>> y
2
>>> x, y = y, x	# 不使用中间变量交换两个变量的值
>>> x
2
>>> y
1
# 元祖拆包

>>> divmod(20, 8)
(2, 4)
>>> t = (20, 8)
>>> divmod(*t)
(2, 4)
>>> quotient, remainder = divmod(*t)
>>> quotient, remainder
(2, 4)
# 用*来处理剩下的元素

>>> a, b, *rest = range(5)
>>> a, b, rest
(0, 1, [2, 3, 4])
>>> a, b, *rest = range(3)
>>> a, b, rest
(0, 1, [2])
>>> a, b, *rest = range(2)
>>> a, b, rest
(0, 1, [])
>>> a, b, *rest = range(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected at least 2, got 1)


>>> a, *body, c, d = range(5)
>>> a, body, c, d
(0, [1, 2], 3, 4)
>>> *head, b, c, d = range(5)
>>> head, b, c, d
([0, 1], 2, 3, 4)
# 嵌套元组拆包

>>> arr = [('Tom', 10, (90, 80)), ('Lucy', 11, (89, 100))]
>>> for name, age, (math_grade, chinese_grade) in arr:
...     print(f"{name}, {age}, {math_grade}, {chinese_grade}")
...
Tom, 10, 90, 80
Lucy, 11, 89, 100
# 具名元组

>>> from collections import namedtuple
>>> City = namedtuple('City', 'name country population coordinates')
>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
>>> tokyo
City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
>>> tokyo.population
36.933
>>> tokyo.coordinates
(35.689722, 139.691667)
>>> tokyo[1]
'JP'
>>>
>>> City._fields
('name', 'country', 'population', 'coordinates')
>>> LatLong = namedtuple('LatLong', 'lat long')
>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
>>> delhi = City._make(delhi_data)
>>> delhi._asdict()
{'name': 'Delhi NCR', 'country': 'IN', 'population': 21.935, 'coordinates': LatLong(lat=28.613889, long=77.208889)}
>>> for key, value in delhi._asdict().items():
...     print(key + ':', value)
...
name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)
  • 元组官方文档

切片

>>> s = 'bicycle'
>>> s[::3]
'bye'
>>> s[::-1]
'elcycib'
>>> s[::-2]
'eccb'
>>>
>>>
>>> l = list(range(6))
>>> l[:2]
[0, 1]
>>> l[2:]
[2, 3, 4, 5]
>>> l[slice(2, 5)]
[2, 3, 4]
>>>
>>> l
[0, 1, 2, 3, 4, 5]
>>> del l[2:4]
>>> l
[0, 1, 4, 5]
>>> l[1:3] = [2, 3]
>>> l
[0, 2, 3, 5]
>>> l[1:3] = 100
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable
>>> l[1:3] = [100]
>>> l
[0, 100, 5]

对序列使用+和*

>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> 'abc' * 3
'abcabcabc'
>>>
>>> board = [['_'] * 3 for i in range(3)]
>>> board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> board[1][2] = 'X'
>>> board
[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]
>>>
>>> weird_board = [['_'] * 3] * 3	# weird_board[0]、weird_board[1] 和 weird_board[2] 是同一个引用
>>> weird_board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> weird_board[1][2] = 'X'
>>> weird_board
[['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']]

序列的增量赋值

>>> l = [1, 2, 3]
>>> id(l)
4307416704
>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
4307416704

>>> t = (1, 2, 3)
>>> id(t)
4307435648
>>> t *= 2	# 对于不可变对象,此操作生成了新对象,地址已经发生变化
>>> t
(1, 2, 3, 1, 2, 3)
>>> id(t)
4307394816

>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]	# 此操作导致tuple里的可变对象发生变化,并抛异常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])

list.sort方法和内置函数sorted

# list.sort原地修改,而sorted不影响原始的。两者都有reverse和key参数

>>> fruits = ['grape', 'raspberry', 'apple', 'banana']
>>> sorted(fruits)
['apple', 'banana', 'grape', 'raspberry']
>>> fruits
['grape', 'raspberry', 'apple', 'banana']
>>> sorted(fruits, reverse=True)
['raspberry', 'grape', 'banana', 'apple']
>>> sorted(fruits, reverse=True, key=len)
['raspberry', 'banana', 'grape', 'apple']
>>> fruits
['grape', 'raspberry', 'apple', 'banana']
>>> fruits.sort()
>>> fruits
['apple', 'banana', 'grape', 'raspberry']

bisect

# 二分查找等于某值的位置,插入到该值的左侧或右侧

>>> import bisect
>>> lis = [1, 2, 2, 2, 3, 4, 5]
>>> bisect.bisect(lis, 2)
4
>>> bisect.bisect_right(lis, 2)	# bisect和bisect_right一样
4
>>> bisect.bisect_left(lis, 2)
1
>>> bisect.bisect(lis, 3)
5
>>> bisect.bisect_left(lis, 3)
4
>>> bisect.bisect_right(lis, 3)
5

>>> bisect.bisect(lis, 0)
0
>>> bisect.bisect(lis, 9)
7

>>> lis
[1, 2, 2, 2, 3, 4, 5]
>>> bisect.insort(lis, 1)	# insort和insort_right一样,insort_left则是插入左侧
>>> lis
[1, 1, 2, 2, 2, 3, 4, 5]

数组

虽然列表既灵活又简单,但面对各类需求时,我们可能会有更好的选择。比如,要存放 1000 万个浮点数的话,数组(array)的效率要高得多,因为数组在背后存的并不是 float 对象,而是数字的机器翻译,也就是字节表述。

>>> from array import array
>>> from random import random
>>> floats = array('d', (random() for i in range(10**7)))
>>> floats[-1]
0.5888943390247224
>>> fp = open('floats.bin', 'wb')
>>> floats.tofile(fp)
>>> fp.close()
>>> floats2 = array('d')
>>> fp = open('floats.bin', 'rb')
>>> floats2.fromfile(fp, 10**7)
>>> fp.close()
>>> floats2[-1]
0.5888943390247224
>>> floats2 == floats
True
  • 数组官方文档

memoryview

memoryview 是一个内置类,它能让用户在不复制内容的情况下操作同一个数组的不同切片。

>>> numbers = array.array('h', [-2, -1, 0, 1, 2])	# signed short,2 bytes
>>> memv = memoryview(numbers)
>>> len(memv)
5
>>> memv[0]
-2
>>> memv_oct = memv.cast('B')	# unsigned char,1 byte
>>> memv_oct.tolist()
[254, 255, 255, 255, 0, 0, 1, 0, 2, 0] # 255 244=-2, 255 255=-1, 0 0=0, 0 1=1, 0 2 = 2 
>>> memv_oct[5] = 4	# 4 0=1024
>>> numbers
array('h', [-2, -1, 1024, 1, 2])

deque

# collections.deque双向队列是一个线程安全类

>>> from collections import deque
>>> dq = deque(range(10), maxlen=10)
>>> dq
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.rotate(3)
>>> dq
deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)
>>> dq.rotate(-4)
>>> dq
deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)
>>> dq.appendleft(-1)
>>> dq
deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)
>>> dq.extend([11, 22, 33])
>>> dq
deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)
>>> dq.extendleft([10, 20, 30, 40])
>>> dq
deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)
  • deque官方文档

第 3 章 字典和集合

  • 字典官方文档
  • 集合官方文档
# 字典创建
>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> a == b == c == d == e
True

# 字典推导
>>> my_list = [("a", 1), ("b", 2), ("c", 3)]
>>> my_dict = {x: y for x, y in my_list}
>>> my_dict
{'a': 1, 'b': 2, 'c': 3}
>>> my_dict.get('d', -1)
-1
>>> my_dict.setdefault('e', 6)
6
>>> my_dict
{'a': 1, 'b': 2, 'c': 3, 'e': 6}

# defaultdict
>>> import collections
>>> my_dict = collections.defaultdict(list)
>>> my_dict
defaultdict(<class 'list'>, {})
>>> my_dict[0].append(1)	# 键不存在时,值默认是一个list
>>> my_dict
defaultdict(<class 'list'>, {0: [1]})

# __missing__
class StrKeyDict(dict):
   def __missing__(self, key):
      if isinstance(key, str):
         raise KeyError(key)
      return self[str(key)]
   
   def get(self, key, default=None):
      try:
         return self[key]  # __getitem__查不到,会调用__missing__
      except KeyError:
         return default
      
   def __contains__(self, key):
      return key in self.keys() or str(key) in self.keys()


if __name__ == '__main__':
   my_dict = StrKeyDict()
   # get(1)
   # self[1]
   # __getitem__查不到key=1
   # __missing__查self['1']
   # __getitem__查不到key='1'
   # __missing__raise KeyError
   # get捕获KeyError,返回None
   print(my_dict.get(1))   # None

# OrderedDict,在添加键的时候会保持顺序
>>> order_dict = collections.OrderedDict()
>>> order_dict[2] = '2'
>>> order_dict[3] = '3'
>>> order_dict[1] = '1'
>>> order_dict
OrderedDict([(2, '2'), (3, '3'), (1, '1')])

# Counter
>>> ct = collections.Counter('abracadabra')
>>> ct
Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
>>> ct.update('aaaaazzz')
>>> ct
Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
>>> ct.most_common(2)
[('a', 10), ('z', 3)]

# UserDict,因其继承了Mapping.get就不用再实现了,此方法跟StrKeyDict.get实现一样
import collections


class StrKeyDict(collections.UserDict):
   def __missing__(self, key):
      if isinstance(key, str):
         raise KeyError(key)
      return self[str(key)]
      
   def __contains__(self, key):
      return str(key) in self.data
   
   def __setitem__(self, key, item):
      self.data[str(key)] = item

if __name__ == '__main__':
   my_dict = StrKeyDict()
   # get(1)
   # self[1]
   # __getitem__查不到key=1
   # __missing__查self['1']
   # __getitem__查不到key='1'
   # __missing__raise KeyError
   # get捕获KeyError,返回None
   print(my_dict.get(1))   # None

# 不可变映射类型MappingProxyType,下面d_proxy是只读的,但可随d动态变化
>>> from types import MappingProxyType
>>> d = {1:'A'}
>>> d_proxy = MappingProxyType(d)
>>> d_proxy
mappingproxy({1: 'A'})
>>> d_proxy[1]
'A'
>>> d_proxy[2] = 'B'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'mappingproxy' object does not support item assignment
>>> d[2] = 'B'
>>> d_proxy
mappingproxy({1: 'A', 2: 'B'})
>>> d_proxy[2]
'B'
# 集合
>>> l = ['a', 'a', 'a', 'b']
>>> set(l)
{'a', 'b'}

# 集合交并差
>>> a = set([1, 2, 3])
>>> b = set([2, 3, 4])
>>> a & b
{2, 3}
>>> a | b
{1, 2, 3, 4}
>>> a - b
{1}
>>> a ^ b
{1, 4}

# 集合推导
>>> {i for i in range(6)}
{0, 1, 2, 3, 4, 5}

第 4 章 文本和字节序列

  • 字节序列
  • 字符序列
# 字符序列与字节序列
>>> s = 'café'	# 'café' 字符串有4个Unicode字符,在2015年,“字符”的最佳定义是Unicode字符。
>>> type(s)
<class 'str'>
>>> len(s)
4
>>> b = s.encode('utf8')	# 字节序列
>>> b
b'caf\xc3\xa9'
>>> type(b)
<class 'bytes'>
>>> len(b)
5
>>> b.decode('utf8')
'café'

# bytes、bytearray
>>> cafe = bytes('café', encoding='utf_8')
>>> cafe
b'caf\xc3\xa9'	# 前3个字节b'caf'在可打印的ASCII范围内(0~255),后两个字节则不然。
>>> cafe[0]
99
>>> cafe[:1]
b'c'
>>> cafe_arr = bytearray(cafe)
>>> cafe_arr
bytearray(b'caf\xc3\xa9')
>>> cafe_arr[0]
99
>>> cafe_arr[:1]
bytearray(b'c')


# UnicodeEncodeError
# 多数非 UTF 编解码器只能处理 Unicode 字符的一小部分子集。把文本转换成字节序列时,如果目标编码中没有定义某个字符,那就会抛出UnicodeEncodeError 异常,除非把 errors 参数传给编码方法或函数,对错误进行特殊处理。
>>> city = 'São Paulo'
>>> city.encode('utf_8')
b'S\xc3\xa3o Paulo'
>>> city.encode('utf_16')
b'\xff\xfeS\x00\xe3\x00o\x00 \x00P\x00a\x00u\x00l\x00o\x00'
>>> city.encode('iso8859_1')
b'S\xe3o Paulo'
>>> city.encode('cp437')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.8/lib/python3.8/encodings/cp437.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode character '\xe3' in position 1: character maps to <undefined>
>>> city.encode('cp437', errors='ignore') # 跳过无法编码的字符
b'So Paulo'
>>> city.encode('cp437', errors='replace') # 把无法编码的字符替换成 '?'
b'S?o Paulo'
>>> city.encode('cp437', errors='xmlcharrefreplace') # 把无法编码的字符替换成 XML实体
b'S&#227;o Paulo'

# UnicodeDecodeError
# 不是每一个字节都包含有效的 ASCII 字符,也不是每一个字符序列都是有效的 UTF-8 或 UTF-16。因此,把二进制序列转换成文本时,如果假设是这两个编码中的一个,遇到无法转换的字节序列时会抛此异常。
# 另一方面,很多陈旧的8位编码——如 'cp1252'、'iso8859_1'和'koi8_r'——能解码任何字节序列流而不抛出错误,例如随机噪声。因此,如果程序使用错误的8位编码,解码过程悄无声息,而得到的是无用输出。
>>> octets = b'Montr\xe9al'
>>> octets.decode('cp1252')
'Montréal'
>>> octets.decode('koi8_r')
'MontrИal'
>>> octets.decode('utf_8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 5: invalid continuation byte
>>> octets.decode('utf_8', errors='replace')
'Montr�al'

# Python3默认使用UTF-8编码源码,新版GNU/Linux或Mac OS X默认编码是UTF-8,Windows系统不一样
>>> open('cafe.txt', 'w', encoding='utf_8').write('café')
4
>>> open('cafe.txt').read()
'café'

# 文本
.encoding
'UTF-8'
>>> fp2.read()
'café'
>>> fp3 = open('cafe.txt', 'rb')
>>> fp3
<_io.BufferedReader name='cafe.txt'>
>>> fp3.read()
b'caf\xc3\xa9'
# Unicode
import unicodedata
import re


if __name__ == '__main__':
   re_digit = re.compile(r'\d')
   sample = '1\xbc\xb2\u0969\u136b\u216b\u2466\u2480\u3285'
   for char in sample:
      print('U+%04x' % ord(char),
         char.center(6),
         're_dig' if re_digit.match(char) else '-',
         'isdig' if char.isdigit() else '-',
         'isnum' if char.isnumeric() else '-',
         format(unicodedata.numeric(char), '5.2f'),
         unicodedata.name(char),
         sep='\t')
       

在这里插入图片描述

# 正则表达式中的字符串和字节序列
import re

re_numbers_str = re.compile(r'\d+')     # <1>
re_words_str = re.compile(r'\w+')
re_numbers_bytes = re.compile(rb'\d+')  # <2>
re_words_bytes = re.compile(rb'\w+')

text_str = ("Ramanujan saw \u0be7\u0bed\u0be8\u0bef"  # <3>
            " as 1729 = 1³ + 12³ = 9³ + 10³.")        # <4>

text_bytes = text_str.encode('utf_8')  # <5>

print('Text', repr(text_str), sep='\n  ')
print('Numbers')
print('  str  :', re_numbers_str.findall(text_str))      # <6>
print('  bytes:', re_numbers_bytes.findall(text_bytes))  # <7>
print('Words')
print('  str  :', re_words_str.findall(text_str))        # <8>
print('  bytes:', re_words_bytes.findall(text_bytes))    # <9>

在这里插入图片描述

第三部分 把函数视作对象

第 5 章 一等函数

在 Python 中,函数是一等对象(整数、字符串和字典都是一等对象——没什么特别的)。编程语言理论家把“一等对象”定义为满足下述条件的程序实体:

  • 在运行时创建
  • 能赋值给变量或数据结构中的元素
  • 能作为参数传给函数
  • 能作为函数的返回结果
# 把函数视作对象
>>> def factorial(n):
...     '''returns n!'''
...     return 1 if n < 2 else n * factorial(n-1)
...
>>> factorial(42)
1405006117752879898543142606244511569936384000000000
>>> factorial.__doc__
'returns n!'
>>> type(factorial)
<class 'function'>
>>>
>>> fact = factorial
>>> fact
<function factorial at 0x10412d3a0>
>>> fact(5)
120
>>> map(factorial, range(11))
<map object at 0x1047b4c10>
>>> list(map(fact, range(11)))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

# 高阶函数,接受函数为参数,或者把函数作为结果返回的函数是高阶函数(higherorder function),如map、sorted
>>> fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
>>> sorted(fruits, key=len)
['fig', 'apple', 'cherry', 'banana', 'raspberry', 'strawberry']
>>>
>>> def reverse(word):
...     return word[::-1]
...
>>> sorted(fruits, key=reverse)
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']
>>> sorted(fruits, key=lambda word: word[::-1])	# lambda表达式/匿名函数
['banana', 'apple', 'fig', 'raspberry', 'strawberry', 'cherry']

>>> list(map(fact, range(6)))
[1, 1, 2, 6, 24, 120]
>>> [fact(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> list(map(factorial, filter(lambda n: n % 2, range(6))))
[1, 6, 120]
>>> [factorial(n) for n in range(6) if n % 2]
[1, 6, 120]

>>> from functools import reduce
>>> from operator import add
>>> reduce(add, range(100))
4950
>>> sum(range(100))
4950
# 常规对象没有而函数有的属性
>>> class C: pass
...
>>> obj = C()
>>> def func(): pass
...
>>> sorted(set(dir(func)) - set(dir(obj)))
['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__']
# * 和 **

def tag(name, *content, cls=None, **attrs):
   """生成一个或多个HTML标签"""
   if cls is not None:
      attrs['class'] = cls
   if attrs:
      attr_str = ''.join(' %s="%s"' % (attr, value) for attr, value in sorted(attrs.items()))
   else:
      attr_str = ''
   if content:
      return '\n'.join('<%s%s>%s</%s>' % (name, attr_str, c, name) for c in content)
   else:
      return '<%s%s />' % (name, attr_str)

if __name__ == '__main__':
   print(tag('br'))
   print(tag('p', 'hello'))
   print(tag('p', 'hello', 'world'))
   print(tag('p', 'hello', id=33))
   print(tag('p', 'hello', 'world', cls='sidebar'))
   # content='testing' 被 **attrs 接收
   print(tag(content='testing', name="img"))
   
   my_tag = {'name': 'img', 'title': 'Sunset Boulevard', 'src': 'sunset.jpg', 'cls': 'framed'}
   # 在 my_tag 前面加上 **,字典中的所有元素作为单个参数传入,同名键会绑定到对应的具名参数上,余下的则被 **attrs 捕获
   print(tag(**my_tag))

在这里插入图片描述

# 验证一下传入的 **my_tag 都绑定到了哪些参数上
>>> def tag(name, *content, cls=None, **attrs):
...    """生成一个或多个HTML标签"""
...    if cls is not None:
...       attrs['class'] = cls
...    if attrs:
...       attr_str = ''.join(' %s="%s"' % (attr, value) for attr, value in sorted(attrs.items()))
...    else:
...       attr_str = ''
...    if content:
...       return '\n'.join('<%s%s>%s</%s>' % (name, attr_str, c, name) for c in content)
...    else:
...       return '<%s%s />' % (name, attr_str)
...
>>> import inspect
>>> sig = inspect.signature(tag)
>>> my_tag = {'name': 'img', 'title': 'Sunset Boulevard', 'src': 'sunset.jpg', 'cls': 'framed'}
>>> bound_args = sig.bind(**my_tag)
>>> bound_args
<BoundArguments (name='img', cls='framed', attrs={'title': 'Sunset Boulevard', 'src': 'sunset.jpg'})>
>>> for name, value in bound_args.arguments.items():
...     print(name, '=', value)
...
name = img
cls = framed
attrs = {'title': 'Sunset Boulevard', 'src': 'sunset.jpg'}
# 函数注解,Python 对注解所做的唯一的事情是,把它们存储在函数的__annotations__ 属性里。仅此而已,Python 不做检查、不做强制、不做验证,什么操作都不做。换句话说,注解对 Python 解释器没有任何意义。注解只是元数据,可以供 IDE、框架和装饰器等工具使用。写作本书时,标准库中还没有什么会用到这些元数据,唯有inspect.signature() 函数知道怎么提取注解
>>> def f(x:int, y:int) -> int:
...     return max(x, y)
...
>>> f.__annotations__
{'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
# 函数式编程
>>> from functools import reduce
>>> from operator import mul
>>> def fact(n):
...     return reduce(mul, range(1, n+1))
...
>>> fact(5)
120
# 冻结参数
>>> from operator import mul
>>> from functools import partial
>>> triple = partial(mul, 3)
>>> triple(7)
21
>>> list(map(triple, range(1, 10)))
[3, 6, 9, 12, 15, 18, 21, 24, 27]

第 7 章 函数装饰器和闭包

初探装饰器

# 装饰器,装饰器的一大特性是,能把被装饰的函数替换成其他函数。第二个特性是,装饰器在加载模块时立即执行。
>>> def deco(func):
...     def inner():
...             print("running inner()")
...     return inner
...
>>> @deco
... def target():
...     print("running target()")
...
>>> target()
running inner()
>>> target
<function deco.<locals>.inner at 0x10bd2bd80>


# hello.py
registry = []  # <1>

def register(func):  # <2>
    print('running register(%s)' % func)  # <3>
    registry.append(func)  # <4>
    return func  # <5>

@register  # <6>
def f1():
    print('running f1()')

@register
def f2():
    print('running f2()')

def f3():  # <7>
    print('running f3()')

def main():  # <8>
    print('running main()')
    print('registry ->', registry)
    f1()
    f2()
    f3()

if __name__=='__main__':
    main()  # <9>

>>> import hello	# 导入模块时装饰器立即执行
running register(<function f1 at 0x10acf3ce0>)
running register(<function f2 at 0x10acf3d80>)

# python hello.py 
running register(<function f1 at 0x10806df80>)
running register(<function f2 at 0x1080bce00>)
running main()
registry -> [<function f1 at 0x10806df80>, <function f2 at 0x1080bce00>]
running f1()
running f2()
running f3()

变量作用域规则

# 变量作用域规则,Python 编译函数的定义体时,它判断 b 是局部变量,因为在函数中给它赋值了。但调用 f(3) 时,尝试获取局部变量 b 的值时,发现 b 没有绑定值。可查看翻译成的汇编。。。
>>> b = 6
>>> def f(a):
...     print(a)
...     print(b)
...     b = 9
...
>>> f(3)
3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f
UnboundLocalError: cannot access local variable 'b' where it is not associated with a value

# 可以使用 global 让解释器把 b 当成全局变量
>>> b = 6
>>> def f(a):
...     print(a)
...     global b
...     print(b)
...     b = 9
...
>>> f(3)
3
6
>>> b
9

闭包

其实,闭包指延伸了作用域的函数,其中包含函数定义体中引用、但是不在定义体中定义的非全局变量。只有涉及嵌套函数时才有闭包问题。

# 计算平均值——类实现方式
class Averager():

    def __init__(self):
        self.series = []

    def __call__(self, new_value):
        self.series.append(new_value)
        total = sum(self.series)
        return total/len(self.series)
    
if __name__ == '__main__':
    avg = Averager()
    print(avg(10))
    print(avg(11))
    print(avg(12))

在这里插入图片描述

# 计算平均值——闭包实现方式
def make_averager():
    series = []

    def averager(new_value):
        series.append(new_value)	# 没有给series赋值,series不会被视为局部变量,而是自由变量,利用列表是可变的特点
        total = sum(series)
        return total/len(series)

    return averager
    
if __name__ == '__main__':
    avg = make_averager()
    print(avg(10))
    print(avg(11))
    print(avg(12))

在这里插入图片描述

综上,闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定义作用域不可用了,但是仍能使用那些绑定。注意,只有嵌套在其他函数中的函数才可能需要处理不在全局作用域中的外部变量。

nonlocal

# 求平均数——效率改进版
def make_averager():
    count = 0
    total = 0

    def averager(new_value):
        # nonlocal count, total
        count += 1  # 等价为count = count + 1,对变量赋值,count被视为局部变量。数字是不可变数据类型,count = count + 1,其实会隐式创建局部变量 count。这样,count 就不是自由变量了,因此不会保存在闭包中。为了解决这个问题,Python 3 引入了 nonlocal 声明。它的作用是把变量标记为自由变量,即使在函数中为变量赋予新值了,也会变成自由变量。如果为 nonlocal 声明的变量赋予新值,闭包中保存的绑定会更新。
        total += new_value  # 同count,total也被视为局部变量
        return total/count

    return averager
    
if __name__ == '__main__':
    avg = make_averager()
    print(avg(10))  # 报错,UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
    print(avg(11))
    print(avg(12))

一个简单的装饰器,输出函数的运行时间

import time

import functools 

def clock(func):
    def clocked(*args):
        t0 = time.time()
        result = func(*args)
        elapsed = time.time() - t0
        name = func.__name__
        arg_str = ', '.join(repr(arg) for arg in args)
        print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result))
        return result
    return clocked

@clock
def snooze(seconds):
    time.sleep(seconds)

@clock
@functools.lru_cache()  # 标准库中的装饰器,它把耗时函数的结果保存起来,避免传入相同的参数时重复计算
def factorial(n):
    return 1 if n < 2 else n*factorial(n-1)

if __name__ == '__main__':
    print('*' * 40, 'Calling snooze(.123)')
    snooze(.123)
    print('*' * 40, 'Calling factorial(6)')
    print('6! =', factorial(6))

在这里插入图片描述

第四部分 面向对象惯用法

第 8 章 对象引用、可变性和垃圾回收

== 和 is

# == 和 is
== 运算符比较两个对象的值(对象中保存的数据,底层是调用__eq__),而 is 比较对象的标识(id)。

元组的相对不可变性

# 元组不可变,但其引用元素是可变的
>>> t1 = (1, 2, [30, 40])
>>> t2 = (1, 2, [30, 40])
>>> t1 == t2
True
>>> t1 is t2
False
>>> id(t1), id(t2)
(4370239168, 4370215296)
>>> id(t1[-1])
4370235520
>>> t1[-1].append(99)
>>> id(t1[-1])
4370235520
>>> t1
(1, 2, [30, 40, 99])

默认浅拷贝

构造方法或 [:] 做的是浅复制(即复制了最外层容器,副本中的元素是源容器中元素的引用)。如果所有元素都是不可变的,那么这样没有问题,还能节省内存。但是,如果有可变的元素,可能就会导致意想不到的问题。

>>> l1 = [3, [66, 55, 44], (7, 8, 9)]
>>> l2 = list(l1)       # 同l2 = l1[:]
>>> l1.append(100)
>>> l1[1].remove(55)
>>> print('l1:', l1)
l1: [3, [66, 44], (7, 8, 9), 100]
>>> print('l2:', l2)
l2: [3, [66, 44], (7, 8, 9)]
>>> l2[1] += [33, 22]
>>> l2[2] += (10, 11)
>>> print('l1:', l1)
l1: [3, [66, 44, 33, 22], (7, 8, 9), 100]
>>> print('l2:', l2)
l2: [3, [66, 44, 33, 22], (7, 8, 9, 10, 11)]

在这里插入图片描述
在这里插入图片描述
copy 模块提供的 deepcopy 和 copy 函数能为任意对象做深复制和浅复制。

注意,一般来说,深复制不是件简单的事。如果对象有循环引用,那么这个朴素的算法会进入无限循环。deepcopy 函数会记住已经复制的对象,因此能优雅地处理循环引用。

>>> a = [10, 20]
>>> b = [a, 30]
>>> a.append(b)
>>> a
[10, 20, [[...], 30]]
>>> from copy import deepcopy
>>> c = deepcopy(a)
>>> c
[10, 20, [[...], 30]]

函数的参数作为引用时

>>> def f(a, b):
...     a += b
...     return a
...
>>> x, y = 1, 2
>>> f(x, y)
3
>>> x, y
(1, 2)
>>> a, b = [1, 2], [3, 4]
>>> f(a, b)
[1, 2, 3, 4]
>>> a, b
([1, 2, 3, 4], [3, 4])
>>> t = (10, 20)
>>> u = (30, 40)
>>> f(t, u)
(10, 20, 30, 40)
>>> t, u
((10, 20), (30, 40))
# 不要使用可变类型作为参数的默认值,下面的bus2和bus3的passengers是同一个默认值的引用
class HauntedBus:
    """A bus model haunted by ghost passengers"""

    def __init__(self, passengers=[]):  # <1>
        self.passengers = passengers  # <2>

    def pick(self, name):
        self.passengers.append(name)  # <3>

    def drop(self, name):
        self.passengers.remove(name)

>>> bus1 = HauntedBus(['Alice', 'Bill'])
>>> bus1.passengers
['Alice', 'Bill']
>>> bus1.pick('Charlie')
>>> bus1.drop('Alice')
>>> bus1.passengers
['Bill', 'Charlie']
>>> bus2 = HauntedBus()
>>> bus2.pick('Carrie')
>>> bus2.passengers
['Carrie']
>>> bus3 = HauntedBus()
>>> bus3.passengers
['Carrie']
>>> bus3.pick('Dave')
>>> bus2.passengers
['Carrie', 'Dave']
>>> bus2.passengers is bus3.passengers
True
>>> bus1.passengers
['Bill', 'Charlie']


>>> basketball_team = ['Sue', 'Tina', 'Maya', 'Diana', 'Pat']
>>> bus = TwilightBus(basketball_team)
>>> bus.drop('Tina')
>>> bus.drop('Pat')
>>> basketball_team
['Sue', 'Maya', 'Diana']
# 防御可变参数
class TwilightBus:
    """A bus model that makes passengers vanish"""

    def __init__(self, passengers=None):
        if passengers is None:
            self.passengers = []  # <1>
        else:
            self.passengers = passengers  #<2>

    def pick(self, name):
        self.passengers.append(name)

    def drop(self, name):
        self.passengers.remove(name)  # <3>

第 9 章 符合Python风格的对象

"""
A 2-dimensional vector class

# BEGIN VECTOR2D_V0_DEMO

    >>> v1 = Vector2d(3, 4)
    >>> print(v1.x, v1.y)  # <1>
    3.0 4.0
    >>> x, y = v1  # <2>
    >>> x, y
    (3.0, 4.0)
    >>> v1  # <3>
    Vector2d(3.0, 4.0)
    >>> v1_clone = eval(repr(v1))v1_clone = eval(repr(v1))  # <4>
    >>> v1 == v1_clone  # <5>
    True
    >>> print(v1)  # <6>
    (3.0, 4.0)
    >>> octets = bytes(v1)  # <7>
    >>> octets
    b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
    >>> abs(v1)  # <8>
    5.0
    >>> bool(v1), bool(Vector2d(0, 0))  # <9>
    (True, False)
    
    >>> v1_clone = Vector2d.frombytes(bytes(v1))
    >>> v1_clone
    Vector2d(3.0, 4.0)
    >>> v1 == v1_clone
    True

# END VECTOR2D_V0_DEMO
"""

# BEGIN VECTOR2D_V0
from array import array
import math


class Vector2d:
    typecode = 'd'  # <1>

    def __init__(self, x, y):
        self.x = float(x)    # <2>
        self.y = float(y)

    def __iter__(self):
        return (i for i in (self.x, self.y))  # <3>

    def __repr__(self):
        class_name = type(self).__name__
        return '{}({!r}, {!r})'.format(class_name, *self)  # <4>

    def __str__(self):
        return str(tuple(self))  # <5>

    def __bytes__(self):
        return (bytes([ord(self.typecode)]) +  # <6>
                bytes(array(self.typecode, self)))  # <7>

    def __eq__(self, other):
        return tuple(self) == tuple(other)  # <8>

    def __abs__(self):
        return math.hypot(self.x, self.y)  # <9>

    def __bool__(self):
        return bool(abs(self))  # <10>
    
    @classmethod  # 类方法使用 classmethod 装饰器修饰,类方法的第一个参数名为 cls(但是 Python 不介意具体怎么命名)
    def frombytes(cls, octets):  # cls 传入类本身
        typecode = chr(octets[0])  # 从第一个字节中读取 typecode
        memv = memoryview(octets[1:]).cast(typecode)
        return cls(*memv)
# END VECTOR2D_V0

classmethod与staticmethod

classmethod 装饰器,定义操作类,而不是操作实例的方法。因此类方法的第一个参数是类本身,而不是实例。classmethod 最常见的用途是定义备选构造方法。按照约定,类方法的第一个参数名为 cls(但是 Python 不介意具体怎么命名)。

staticmethod 装饰器,定义类的普通方法。但是第一个参数不是特殊的值。

>>> class Demo:
...     @classmethod
...     def classmeth(*args):
...             return args
...     @staticmethod
...     def staticmeth(*args):
...             return args
...
>>> Demo.classmeth()
(<class '__main__.Demo'>,)
>>> Demo.classmeth('param')
(<class '__main__.Demo'>, 'param')
>>> Demo.staticmeth()
()
>>> Demo.staticmeth('param')
('param',)
>>> demo = Demo()
>>> demo.staticmeth()
()
>>> demo.staticmeth('x')
('x',)
>>> demo.classmeth('x')
(<class '__main__.Demo'>, 'x')
# 格式化显示
>>> brl = 1/2.43 # BRL到USD的货币兑换比价
>>> brl
0.4115226337448559
>>> format(brl, '0.4f')
'0.4115'
>>> '1 BRL = {rate:0.2f} USD'.format(rate=brl)
'1 BRL = 0.41 USD'
>>>
>>>
>>> format(42, 'b')
'101010'
>>> format(2/3, '.1%')
'66.7%'
>>>
>>> from datetime import datetime
>>> now = datetime.now()
>>> format(now, '%H:%M:%S')
'22:11:34'
>>> "It's now {:%I:%M %p}".format(now)
"It's now 10:11 PM"

参考资料

[1] 《流畅的Python》作者:[巴西] Luciano Ramalho 译者:安道 吴珂
[2] 《流畅的Python》代码库
[3] Python官方文档
[4] 菜鸟教程Python

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1467082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Leetcode 209.长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;返回 0 。 示例 1&#xff1a; 输入&…

Linux---权限管理(ACL权限、特殊位和隐藏属性)

目录 1.ACT权限 1.1什么是ACT权限 1.2ACT图解 2.操作步骤 2.1添加测试目录、用户、组&#xff0c;并将用户添加到组 2.2修改目录的所有者和所属组 2.3设定权限 2.4为临时用户分配权限 2.4.1添加临时用户 2.4.2为临时用户分配特定权限 2.4.3查看目录权限&#xff0c;注…

Moment.js——轻松处理日期和和时间,有实例代码

hello&#xff0c;我是贝格前端工场&#xff0c;本期给大家带来便捷的处理日期和时间的js库&#xff1a;Moment.js&#xff0c;用这个类库处理时间将会十分方便&#xff0c;欢迎老铁们点赞关注&#xff0c;如有前端定制开发需求可以私信我们。 一、Moment.js的简介和功能 Mom…

C++多线程同步(上)

多线程同步 引言总述详情互斥锁示例运行结果分析条件变量示例一实现分析优化运行结果示例二实现代码运行结果示例三实现代码运行结果读写锁示例实现代码注意分析运行结果附言实现运行结果运行结果个人心得引言 项目中使用多线程,会遇到两种问题,一种是对共享资源的访问时需要…

echarts多y轴样式重叠问题

1、主要属性设置 yAxis: [{//y轴1nameTextStyle: {align: "right",padding: 0}},{//y轴2nameTextStyle: {align: "left",padding: 0}},{//y轴3axisLabel: {margin: 50},nameTextStyle: {align: "left",padding: [0, 0, 0, 50]},axisPointer: {l…

Web基础02 -CSS+CSS3

目录 一、CSS 1.CSS盒模型 2.元素宽度计算 3.元素高度计算 4.宽度和高度的度量单位 5.设置元素的极限宽高 6.CSS属性&#xff08;第二部分&#xff09; &#xff08;1&#xff09;纯色背景 &#xff08;2&#xff09;图片背景 &#xff08;3&#xff09;列表样式 &am…

Tomcat信创平替之TongWEB(东方通),安装步骤

我的系统: 银河麒麟桌面系统V10(SP1) 开局先吐槽一下(当然国产也是需要大量时间与金钱的投入),感觉国产软件进入死循环:国家推动国产→国产收费→还要钱?→用国外开源→国产无发普及→靠国家推动 正题: 1.先进入东方通申请使用 2.客服会发送一个TongWEB包与license.dat给你…

leet hot 100-1 两数之和

两数之和 原题链接思路代码 原题链接 leet hot 100-1 1. 两数之和 思路 可以把当前数字放到容器里面去 当我们遍历一个新的数字的时候 减一下与目标值的差 然后得到的结果在容器里面查看是否存在 时间复杂度O(n) 空间复杂度(n) 代码 class Solution { public:vector<…

【漏洞复现】大华DSS视频管理系统信息泄露漏洞

Nx01 产品简介 大华DSS数字监控系统是一个在通用安防视频监控系统基础上设计开发的系统&#xff0c;除了具有普通安防视频监控系统的实时监视、云台操作、录像回放、报警处理、设备治理等功能外&#xff0c;更注重用户使用的便利性。 Nx02 漏洞描述 大华DSS视频管理系统存在信…

Redis能保证数据不丢失吗?

引言 大家即使没用过Redis&#xff0c;也应该都听说过Redis的威名。 Redis是一种Nosql类型的数据存储&#xff0c;全称Remote Dictionary Server&#xff0c;也就是远程字典服务器&#xff0c;用过Dictionary的应该都知道它是一种键值对&#xff08;Key-Value&#xff09;的数…

Spring中的ApplicationContext.publishEvent

简单理解 其实就是监听处理。比如找工作平台上&#xff0c;雇主 employer 发布自己的雇佣条件&#xff0c;目的是平台中有符合条件的求职者时&#xff0c;及时向雇主推荐。求职者发布简历&#xff0c;当平台发现某个求职者比较符合条件&#xff0c;就触发被动&#xff0c;推荐…

【刷题记录】链表的回文结构

本系列博客为个人刷题思路分享&#xff0c;有需要借鉴即可。 1.题目链接&#xff1a; LINK 2.详解思路&#xff1a; 思路&#xff1a;思路&#xff1a;先找到中间节点&#xff0c;然后逆置后半部分链表&#xff0c;一个指针指向链表的头节点&#xff0c;再一个指针指向逆置的头…

Stable Diffusion 3 发布,AI生图效果,再次到达全新里程碑!

AI生图效果&#xff0c;再次到达全新里程碑&#xff01; Prompt&#xff1a;Epic anime artwork of a wizard atop a mountain at night casting a cosmic spell into the dark sky that says "Stable Diffusion 3" made out of colorful energy 提示&#xff08;意译…

Kafka:kafka的主从模式和故障切换 ②

一、Kafka整体架构图 二、Kafka原题回答 Kafka集群有主从模式吗&#xff1f; Kafka集群实际上并没有严格意义上的主从模式。Kafka的设计是基于分布式的&#xff0c;每个Topic都会切分为多个Partition&#xff0c;每个Partition都有一个Leader和多个Follower。 所有的读写操作…

Linux设备模型(二) - kset/kobj/ktype APIs

一&#xff0c;kobject_init_and_add 1&#xff0c;kobject_init_and_add实现 /** * kobject_init_and_add() - Initialize a kobject structure and add it to * the kobject hierarchy. * kobj: pointer to the kobject to initialize * ktype: p…

架构篇36:微服务架构最佳实践 - 基础设施篇

文章目录 自动化测试自动化部署配置中心接口框架API 网关服务发现服务路由服务容错服务监控服务跟踪服务安全小结每项微服务基础设施都是一个平台、一个系统、一个解决方案,如果要自己实现,其过程和做业务系统类似,都需要经过需求分析、架构设计、开发、测试、部署上线等步骤…

多线程访问共享对象的线程安全问题

如下所示 主线程有一个类A&#xff0c;并且主线程启动后创建了一个子线程t1子线程t1需要访问主线程类A的方法func class A { public:A(){cout<<"A()"<<endl;}~A(){cout<<"~A()"<<endl;}void func(){cout<<"this is a…

了解网络延迟-MDN文档学习笔记

了解延迟 查看更多学习笔记&#xff1a;GitHub&#xff1a;LoveEmiliaForever MDN中文官网 CDN CDN (内容分发网络) 指的是一组分布在各个地区的服务器 这些服务器存储着数据的副本&#xff0c;因此服务器可以根据哪些服务器与用户距离最近&#xff0c;来满足数据的请求 CD…

PostgreSQL索引篇 | BTree

B-Tree索引 &#xff08;本文为《PostgreSQL数据库内核分析》一书的总结笔记&#xff0c;需要电子版的可私信我&#xff09; B树特点&#xff1a; 非叶子节点含一个或多个关键字值和子节点指针&#xff0c;不指向实际数据的存储位置所有关键字都是叶子节点&#xff0c;每个叶…

RabbitMQ(一):消息队列MQ

目录 1 消息队列MQ1.1 MQ简介1、什么是MQ2、MQ的优势流量削峰应用解耦异常处理数据分发分布式事务 3、消息中间件的弊端4、常用的MQ 1.2 MQ中几个基本概念1.3 MQ的通信模式1.4 消息的发布策略1.5 常用消息中间件协议1、AMQP协议2、MQTT协议3、OpenMessage协议4、kafaka协议 1 消…