学习总结:Python高级编程第2版-语法最佳实践-类级别以下
字符串与字节
集合类型
迭代器
生成器
装饰器
上下文管理器 - with语句
for … else …
函数注解
字符串与字节
str: 字符串
bytes: 字节数组
bytearray: 可变字节数组
1 2 3 4 5 6 7 8 9 >>> print (bytes ([100 ,121 ,101 ]))b'dye' >>> list (b'dye' )[100 , 121 , 101 ] >>> m = b"你好" File "<stdin>" , line 1 SyntaxError: bytes can only contain ASCII literal characters.
Unicode字符串中包含无法用字节表示的”抽象”文本. 因此如果Unicode字符串没有被转换成二进制数据的话,是无法保存在磁盘中或通过网络发送的 。
将字符串对象编码为字节序列的方式:
str.encode(encoding, errors)
bytes(source, encoding, errors)
将二进制数据转化为字符串的方式:
bytes.decode(encoding, errors)
str(source, encoding, error)
1 2 3 4 5 6 7 8 9 >>> "你好" .encode()b'\xe4\xbd\xa0\xe5\xa5\xbd' >>> t = "你好" .encode()>>> tb'\xe4\xbd\xa0\xe5\xa5\xbd' >>> t.decode()'你好' >>> print (type (t))<class 'bytes '>
数据结构进阶 列表 下面的用法几乎适用于任何可迭代对象
列表推导式 1 2 >>> [i for i in range (10 ) if i % 2 == 0 ][0 , 2 , 4 , 6 , 8 ]
enumerate(枚举) 1 2 3 4 5 6 >>> for i, ele in enumerate ([1 ,2 ,3 ]):... print (i, ele)... 0 1 1 2 2 3
zip 压包解包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 >>> for item in zip ([1 ,2 ,3 ], [4 ,5 ]):... print (item)... (1 , 4 ) (2 , 5 ) >>> for item in zip (*zip ([1 ,2 ,3 ], [4 ,5 ])):... print (item)... (1 , 2 ) (4 , 5 ) >>> a,b,*c = 1 ,2 ,3 ,4 >>> a,b,c(1 , 2 , [3 , 4 ])
字典 字典推导 1 2 >>> {i:i*2 for i in (1 ,2 ,3 ,4 ) if i % 2 == 0 }{2 : 4 , 4 : 8 }
keys() values() items() 三者返回的是视图对象
集合 集合推导 1 2 >>> {i for i in (1 ,2 ,3 ,2 )}{1 , 2 , 3 }
set()和frozenset() frozenset() 返回一个冻结的集合,冻结后集合不能再添加或删除任何元素。
collections库
Counter:字典的子类,提供了可哈希对象的计数功能
defaultdict:字典的子类,提供了一个工厂函数,为字典查询提供了默认值
OrderedDict:字典的子类,保留了他们被添加的顺序
namedtuple:创建命名元组子类的工厂函数
deque:类似列表容器,实现了在两端快速添加(append)和弹出(pop)
ChainMap:类似字典的容器类,将多个映射集合到一个视图里面
迭代器 迭代器只不过是实现迭代器协议的容器对象。它基于以下两个方法:
__next__:返回容器下一个元素
__iter__:返回迭代器本身
使用iter函数 迭代器可以利用内置iter函数和一个序列来构建,如下例:
1 2 3 4 5 6 7 8 9 10 11 >>> obj = iter ([1 ,2 ,3 ])>>> next (obj)1 >>> next (obj)2 >>> next (obj)3 >>> next (obj)Traceback (most recent call last): File "<stdin>" , line 1 , in <module> StopIteration
当遍历结束后,可以得到StopIteration异常,捕获到这种异常可停止循环。
1 2 3 4 5 6 7 >>> obj = iter ([1 ,2 ,3 ])>>> for i in obj:... print (i)... 1 2 3
自定义迭代器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class MyIter (object ): def __init__ (self, step ): self.step = step def __next__ (self ): """return the next element""" if self.step <= 0 : raise StopIteration self.step -= 1 return self.step+1 def __iter__ (self ): """return the iterator self""" return self
1 2 3 4 5 6 7 >>> for ele in MyIter(4 ):... print (ele)... 4 3 2 1
生成器 基于yield语句,生成器可以暂停函数并返回一个中间结果。该函数会保存执行上下文,稍后在必要时可以恢复。
斐波那契数列简单生成器 1 2 3 4 5 def fibonacci (): a, b = 0 , 1 while True : yield b a, b = b, a + b
1 2 3 4 5 6 7 8 9 10 11 >>> fib = fibonacci()>>> next (fib)1 >>> next (fib)1 >>> next (fib)2 >>> next (fib)3 >>> type (fib)<class 'generator '>
该函数返回一个generator对象,该对象是一个特殊的迭代器,它知道如何保存上下文。
上述斐波那契数列迭代器对象可以被无限次调用,就像是数列一样。
send函数 send函数的作用和next类似,但会将send函数内部传入的值变为yield的返回值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 >>> def MyGenerator ():... value = yield "Hello" ... yield value... >>> gen = MyGenerator()>>> next (gen)'Hello' >>> next (gen)>>> next (gen)Traceback (most recent call last): File "<stdin>" , line 1 , in <module> StopIteration >>> gen = MyGenerator()>>> next (gen)'Hello' >>> gen.send("Hi" )'Hi' >>> gen = MyGenerator()>>> gen.send("Hi" )Traceback (most recent call last): File "<stdin>" , line 1 , in <module> TypeError: can't send non-None value to a just-started generator >>> gen = MyGenerator() >>> gen.send(None) ' Hello' >>> gen.send("Hi") ' Hi'
send函数可以根据客户端代码来改变自身行为,为了完成这一行为,还添加了两个函数:
throw:允许客户端发送要抛出的各类异常
close:引发特定异常,GeneratorExit
类成员函数作为生成器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 >>> class A :... def fibonacci (self ):... a, b = 0 , 1 ... while True :... yield b... a, b = b, a + b... >>> aa = A()>>> for i, obj in enumerate (aa.fibonacci()):... print (i, obj)... if i > 5 :... break ... 0 1 1 1 2 2 3 3 4 5 5 8 6 13
装饰器 装饰器是一个可调用对象,即函数或者实现了__call__
方法的类。
@staticmethod和@classmethod
@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。
@staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
@classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class A : def static_method (): print ("staticmethod" ) static_method = staticmethod (static_method) def class_method (cls ): cls.static_method() print ("classmethod" ) class_method = classmethod (class_method) class A : @staticmethod def static_method (): print ("staticmethod" ) @classmethod def class_method (cls ): cls.static_method() print ("classmethod" )
无参装饰器 作为一个函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def say_sth (words="Hello" ): print (words) def decorator (func ): def wrapper (*args, **kwargs ): print ("%s 调用" % func.__name__) return func(*args, **kwargs) return wrapper say_sth = decorator(say_sth) say_sth("Hi~" ) def decorator (func ): def wrapper (*args, **kwargs ): print ("%s 调用" % func.__name__) return func(*args, **kwargs) return wrapper @decorator def say_sth (words="Hello" ): print (words) say_sth("Hi~" )
作为一个类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class DecoratorClass : def __init__ (self, function ): self.function = function def __call__ (self, *args, **kwargs ): print ("%s 调用" % self.function.__name__) return self.function(*args, **kwargs) def say_sth (words="Hello" ): print (words) say_sth = DecoratorClass(say_sth) say_sth("Hi~" ) class DecoratorClass : def __init__ (self, function ): self.function = function def __call__ (self, *args, **kwargs ): print ("%s 调用" % self.function.__name__) return self.function(*args, **kwargs) @DecoratorClass def say_sth (words="Hello" ): print (words) say_sth("Hi~" )
带参装饰器 作为一个函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 def say_sth (words="Hello" ): print (words) def decorator (say=True ): def inner_wrapper (func ): def wrapper (*args, **kwargs ): if say: print ("%s 调用" % func.__name__) return func(*args, **kwargs) return wrapper return inner_wrapper say_sth = decorator(say=False )(say_sth) say_sth("Hi~" ) def decorator (say=True ): def inner_wrapper (func ): def wrapper (*args, **kwargs ): if say: print ("%s 调用" % func.__name__) return func(*args, **kwargs) return wrapper return inner_wrapper @decorator(say=False ) def say_sth (words="Hello" ): print (words) say_sth("Hi~" )
作为一个类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class DecoratorClass : def __init__ (self, say=True ): self.say = say def __call__ (self, func ): def wrapper (*args, **kwargs ): if self.say: print ("%s 调用" % func.__name__) return func(*args, **kwargs) return wrapper def say_sth (words="Hello" ): print (words) say_sth = DecoratorClass(say=False )(say_sth) say_sth("Hi~" ) class DecoratorClass : def __init__ (self, say=True ): self.say = say def __call__ (self, func ): def wrapper (*args, **kwargs ): if self.say: print ("%s 调用" % func.__name__) return func(*args, **kwargs) return wrapper @DecoratorClass(say=False ) def say_sth (words="Hello" ): print (words) say_sth("Hi~" )
保存函数元数据 上述示例均未保存函数的元数据(主要是文档字符串和原始函数名)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 >>> class DecoratorClass :... def __init__ (self, say=True ):... self.say = say... ... def __call__ (self, func ):... def wrapper (*args, **kwargs ):... """wrapper doc""" ... if self.say:... print ("%s 调用" % func.__name__)... return func(*args, **kwargs)... return wrapper... >>> @DecoratorClass(say=True )... def say_sth (words="Hello" ):... """say_sth doc""" ... print (words)... >>> say_sth.__name__'wrapper' >>> say_sth.__doc__'wrapper doc'
为了解决这个问题,我们需要使用functools中的wraps()装饰器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 >>> from functools import wraps>>> class DecoratorClass :... def __init__ (self, say=True ):... self.say = say... ... def __call__ (self, func ):... @wraps(func)... def wrapper (*args, **kwargs ):... """wrapper doc""" ... if self.say:... print ("%s 调用" % func.__name__)... return func(*args, **kwargs)... return wrapper... >>> @DecoratorClass(say=True )... def say_sth (words="Hello" ):... """say_sth doc""" ... print (words)... >>> say_sth.__name__'say_sth' >>> say_sth.__doc__'say_sth doc'
上下文管理器 - with 语句
关闭一个文件
释放一个锁
创建一个临时的代码布丁
在特殊环境运行中受保护的代码
作为一个类 任何实现了上下文管理器协议的对象都可以用作上下文管理器,该协议包含两个方法:
__enter__(self)
: 任何返回值都会绑定到指定的as子句
__exit__(self, exc_type, exc_value, traceback)
: 退出时需要执行的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class FileOpen : def __init__ (self,filename, mode, encoding='utf-8' ): self.filename = filename self.mode = mode self.encoding=encoding def __enter__ (self ): self.fp = open (self.filename, self.mode, encoding=self.encoding) return self.fp def __exit__ (self, exc_type, exc_value, traceback ): self.fp.close() with FileOpen("test.txt" , 'r' , encoding='utf-8' ) as f: print (f.readline())
作为一个函数 使用contextlib模块,yield分割语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import contextlib@contextlib.contextmanager def FileOpen (file_name, mode, encoding='utf-8' ): file_handler = open (file_name, mode, encoding='utf-8' ) try : yield file_handler except Exception as exc: print ('the exception was thrown' ) finally : file_handler.close() with FileOpen("test1.txt" , 'r' , encoding='utf-8' ) as f: print (f.readline())
for … else … 语句 else子句在for循环语句中正常循环结束才会执行,如果由于break语句退出循环,则else子句不会被执行。
1 2 3 4 5 6 >>> for i in range (10 ):... pass ... else :... print ("no break" )... no break
函数注解 可以指定参数类型和返回值类型,但是实际调用时,并不会强制要求参数与注解类型一致。
1 2 3 4 5 6 7 >>> def test (a: str , b: int = 2 ) -> str :... return a + str (b)... >>> test.__annotations__{'a' : <class 'str '>, 'b ': <class 'int '>, 'return ': <class 'str '>} >>> test ("11" , "33" ) '1133'