python你所不知道的一些技巧:列表推导式,迭代器与生成器,装饰器,类的特殊方法(魔法方法),类的装饰器

目录

主要包括列表推导式,迭代器与生成器,装饰器,类的特殊方法(魔法方法),类的装饰器等等

列表推导式

square = []
for i in range(10):
    square.append(i**2)
print(square)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 利用lambda表达式重构上述代码
# map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
# list()函数可以将map()返回的Iterator转换为list
Iterator = map(lambda x: x**2, range(10))
square = list(Iterator)
print(square)

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 使用列表生成式
square = [x**2 for x in range(10)]
print(square)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 其他类型的列表表达式
[x+y for x in 'ABC' for y in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
# 列表表达式中使用if语句
[x for x in range(1, 11) if x % 2 == 0]
[2, 4, 6, 8, 10]
# 列表表达式中同时使用if语句和for语句
[x for x in range(1, 11) if x % 2 == 0 for y in range(1, 11) if y % 3 == 0]

[2, 2, 2, 4, 4, 4, 6, 6, 6, 8, 8, 8, 10, 10, 10]
# 列表表达式中同时使用if语句和for语句
print([(x,y) for x in [1,2,3] for y in [3,1,4] if x != y])
# 等价于
combination = []
for x in [1,2,3]:
    for y in [3,1,4]:
        if x != y:
            combination.append((x,y))
print(combination)
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

迭代器与生成器

大多数容器对象都可以使用 for 语句,这种访问风格清晰、简洁又方便。 迭代器的使用非常普遍并使得 Python 成为一个统一的整体。 在幕后,for 语句会在容器对象上调用 iter()。 该函数返回一个定义了 __next__() 方法的迭代器对象,此方法将逐一访问容器中的元素。 当元素用尽时,__next__() 将引发 StopIteration 异常来通知终止 for 循环。

for element in [1, 2, 3, 4, 5]:
    print(element)
1
2
3
4
5
# 可以使用next()函数来调用__next__()方法的迭代器对象
s = 'abc'
it = iter(s)
it
print(next(it))
print(next(it))
print(next(it))
print(next(it))
a
b
c



---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-21-0603a1158441> in <module>
      6 print(next(it))
      7 print(next(it))
----> 8 print(next(it))


StopIteration: 
# 另外一种调用__next__()方法的方法
n = iter([1, 2, 3])
print(n.__next__())
print(n.__next__())
print(n.__next__())

1
2
3
# 第三种调用__next__()方法的方法
n = iter([1, 2, 3])
print(next(n))
print(next(n))
print(next(n))
print(next(n))
1
2
3



---------------------------------------------------------------------------

StopIteration                             Traceback (most recent call last)

<ipython-input-27-39a89d3766fd> in <module>
      4 print(next(n))
      5 print(next(n))
----> 6 print(next(n))


StopIteration: 

看过迭代器协议的幕后机制,给你的类添加迭代器行为就很容易了。 定义一个 __iter__() 方法来返回一个带有 __next__() 方法的对象。 如果类已定义了__next__(),则 __iter__() 可以简单地返回 self:

class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data): 
        # 构造函数,初始化对象,传入一个可迭代对象,并将其转换为列表
        self.data = data
        self.index = len(data)

    def __iter__(self): # 返回对象本身
        return self

    def __next__(self): # 返回下一个元素
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]
rev = Reverse('spam')
iter(rev)
for char in rev:
    print(char)
m
a
p
s

生成器

生成器 是一个用于创建迭代器的简单而强大的工具。 它们的写法类似于标准的函数,但当它们要返回数据时会使用 yield 语句。 每次在生成器上调用 next() 时,它会从上次离开的位置恢复执行(它会记住上次执行语句时的所有数据值)。 一个显示如何非常容易地创建生成器的示例如下:

with open('*.txt') as f:
    for line in f:
        print(line, end='')
# 用生成器表达式来重构上述代码
def read_file():
    with open('*.txt') as f:
        for line in f:
            yield line
---------------------------------------------------------------------------

OSError                                   Traceback (most recent call last)

<ipython-input-33-96202d7342ea> in <module>
----> 1 with open('*.txt') as f:
      2     for line in f:
      3         print(line, end='')


OSError: [Errno 22] Invalid argument: '*.txt'
def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]
for char in reverse('spam'):
    print(char)
m
a
p
s

可以用生成器来完成的操作同样可以用前一节所描述的基于类的迭代器来完成。 但生成器的写法更为紧凑,因为它会自动创建 iter() 和 next() 方法。

另一个关键特性在于局部变量和执行状态会在每次调用之间自动保存。 这使得该函数相比使用 self.index 和 self.data 这种实例变量的方式更易编写且更为清晰。

除了会自动创建方法和保存程序状态,当生成器终结时,它们还会自动引发 StopIteration。 这些特性结合在一起,使得创建迭代器能与编写常规函数一样容易。

装饰器

在一些第三方库,比如说pytest中会使用到装饰器。 Python-装饰器(wrapper)

# 先理解函数的调用,也就是函数的传入参数可以是一个函数名
def f1():
    print('f1')
def g(func):
    print(func,type(func))
    func()
if __name__ == '__main__':
    g(f1)
<function f1 at 0x00000248DC9A2EE0> <class 'function'>
f1
import logging
# logging.warning('Watch out!')  # will print a message to the console
logging.basicConfig(level=logging.DEBUG)
def foo():
    logging.info('执行foo函数')
    print('foo')
def bar():
    logging.info('执行bar函数')
    print('bar')
if __name__ == '__main__':
    foo()
    bar()

foo
bar
# 每个函数都写一遍logging.info(),这样会导致代码冗余,可以写个函数
import logging
logging.basicConfig(level=logging.DEBUG)
def log(func):
 
    logging.info(f'执行{func.__name__}函数')
    return func()

def foo():
    print('foo')

def bar():
    print('bar')
if __name__ == '__main__':
    log(foo)
    log(bar)
foo
bar
# 函数还是太麻烦了,可以在函数里面再写一个函数
# python装饰器用于拓展原来函数功能的一种函数,
# 这个函数的返回值也是一个函数。


import logging
logging.basicConfig(level=logging.DEBUG)
def use_logging(func): #装饰器函数
    def wrapper():
        logging.info(f'执行{func.__name__}函数')
        func()
    return wrapper
def foo():
    print('foo')
def bar():
    print('bar')
if __name__ == '__main__':
    foo = use_logging(foo)
    foo()
    bar = use_logging(bar)
    bar()
INFO:root:执行foo函数
INFO:root:执行bar函数


foo
bar
# 这样每次调用还要声明一下,太麻烦了,可以使用@符号装饰器的知识,这样就不用每次都声明了
import logging
logging.basicConfig(level=logging.DEBUG)
def use_logging(func): # 装饰器函数,func是被装饰的函数
    def wrapper():
        logging.info(f'执行{func.__name__}函数')
        func()
    return wrapper
@use_logging    # 语法糖 @装饰器函数名 @等价于func = use_logging(func)
# 每次调用函数的时候,都会先调用use_logging函数,然后再调用函数本身,这就是装饰器的作用
def foo():
    print('foo')
@use_logging
def bar():
    print('bar')
if __name__ == '__main__':
    foo()
    bar()
INFO:root:执行foo函数
INFO:root:执行bar函数


foo
bar
# 装饰器@use_logging里面还可以加参数
import logging
logging.basicConfig(level=logging.DEBUG)
def use_logging(level='info'): # 默认level级别是info
    # 装饰器函数里面再增加一个装饰器
    def decractor(func):
        def wrapper(*args,**kwargs):
            if level=='debug':
                logging.debug(f'执行{func.__name__}函数')
            elif level=='info':
                logging.info(f'执行{func.__name__}函数')
            elif level=='warning':
                logging.warning(f'执行{func.__name__}函数')
            elif level == 'error':
                logging.error(f'执行{func.__name__}函数')
            func(*args,**kwargs)
        return wrapper
    return decractor
@use_logging()    
# 每次调用函数的时候,都会先调用use_logging函数,然后再调用函数本身,这就是装饰器的作用
def foo():
    print('foo')
@use_logging(level = 'debug')
def bar():
    print('bar')
if __name__ == '__main__':
    foo()
    bar()
INFO:root:执行foo函数
DEBUG:root:执行bar函数


foo
bar

类的特殊方法 魔法方法

在Python中以两个下划线开头的方法,initstrdoc、__new__等,被称为”魔术方法”(Magic methods)。魔术方法在类或对象的某些事件出发后会自动执行,如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写。

# 最常见的是在class里面的init构造器
class Config:
    def __init__(self,baseip,port):
        print('__init__')
        self.baseip = baseip
        self.port = port

# 实例化一个类
if __name__ == '__main__':
    config = Config(baseip='127.0.0.1',port = 3000)
    print(config.baseip)
    print(config.port)
__init__
127.0.0.1
3000
class People(object):
    # 创建对象
    def __new__(cls, *args, **kwargs):
        print("触发了构造方法")
        ret = super().__new__(cls) # 调用父类的__new__()方法创建对象
        return ret ## 将对象返
    # 实例化对象
    def __init__(self, name, age):
        self.name = name
        self.age = age
        print("初始化方法")
    #  删除对象
    #   del 对象名或者程序执行结束之后
    def __del__(self):
        print("析构方法,删除对象")


if __name__ == '__main__':
    p1 = People('xiaoming', 16)
触发了构造方法
初始化方法
析构方法,删除对象
# 斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13
# 特别指出:第0项是0,第1项是第一个1。从第三项开始,每一项都等于前两项之和。
class Fib(object):
    def __init__(self):
        pass
    def __call__(self,num):
        a,b = 0,1;
        self.l=[]

        for i in range (num):
            self.l.append(a)
            a,b= b,a+b
        return self.l
    def __str__(self):
        return str(self.l)
    __rept__=__str__ 

f = Fib()
print(f(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

类的装饰器

Python小技巧:装饰器(Decorator)


class Foo:
    def __init__(self,func):
        self.func = func
    def __call__(self,*args,**kwargs):
        print('before __call__')
        self.func()
        print('after __call__')
@Foo
def bar():
    print('bar')

if __name__ == '__main__':
    bar()
before __call__
bar
after __call__
import logging
from functools import wraps

from enum import Enum
class Level(Enum):
    debug = 0
    info = 1
    warn = 2
    error = 3


class UseLogging:

    def __init__(self,level:Level):
        self.level = level
        logging.basicConfig(level=logging.DEBUG)


    def __call__(self, func):
        @wraps(func)
        def decorator(*args, **kwargs):
            if self.level == Level.debug:
                logging.debug(f'正在执行{func.__name__}')
            elif self.level == Level.info:
                logging.info(f'正在执行{func.__name__}')
            elif self.level == Level.warn:
                logging.warning(f'正在执行{func.__name__}')
            elif self.level == Level.error:
                logging.error(f'正在执行{func.__name__}')
            func(*args, **kwargs)
        return decorator

@UseLogging(level=Level.warn)
def bar(name,**kwargs):
    print('bar',name,kwargs)

if __name__ == '__main__':
    bar("xiaoming",k = 10)
WARNING:root:正在执行bar


bar xiaoming {'k': 10}

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦