【python】复习细节,常用知识点01

1.input返回的数据类型为str,如果输入数字需要转换类型

2.不可变对象:tuple,string,int,float,bool

​ 为什么不可变?因为这个变量指向的地址是不变的!

3.默认参数:使用时一定要指向不变对象!!!

4.可变参数:直接在变量面前添加*即可,参数此时变为tuple!

5.关键字参数:使用两个**,此时参数为dict

# 如果传入的参数也是字典,有一个简单的使用方法
def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

extra = {'city': 'Beijing', 'job': 'Engineer'}
person('Jack', 24, **extra)

6.命名关键字参数 :如果要限制输入的关键字只能为某些关键字,可以使用一个*

# 使用方法
# 使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数
# 缺少 *,city和job被视为位置参数
def person(name, age, *, city, job):
    print(name, age, city, job)

# 如果函数定义中已经有一个可变参数了,后面的命名关键字参数就不需要一个特殊分隔符*了,,这个时候命名关键字参数必须传值,否则将报错。
# 由于调用时缺少参数名city和job,Python解释器把前两个参数视为位置参数,后两个参数传给*args,但缺少命名关键字参数导致报错。
# 命名关键字参数可以有缺省值,从而简化调用
def person(name, age, *args, city, job):
    print(name, age, args, city, job)
>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() missing 2 required keyword-only arguments: 'city' and 'job'

7.几种参数的组合顺序:必选参数、默认参数、可变参数、命名关键字参数、关键字参数

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

8.展示下标循环可以使用enumerate函数,把可迭代对象变成索引-元素对形式

>>> for i, value in enumerate(['A', 'B']):
...     print(i, value)
0 A
1 B

# enumerate()语法
enumerate(sequence, [start=0])
1.sequence -- 一个序列、迭代器或其他支持迭代对象。
2.start -- 下标起始位置。

9.列表生成式:几个我认为重要的使用方法。

# 两个变量
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']
# 如果if放到了后面,不能加else
# 如果if在for前面,不能不加else
>>> [x for x in range(1, 11) if x % 2 == 0]
[x if x % 2 == 0 else -x for x in range(1, 11)]

10.Iterable和Iterator的区别

可迭代对象Iterable,长度是确定的,已经计算好的。可以使用for循环的都是Iterable

迭代器Iterator,长度不确定,且是实时计算的。可以使用next()的都是Iterator

可使用isinstance()判断是否为Iterator对象。

11.生成器generator

如果我们可以通过前几个元素,推算出后面的所有元素,那么我们就不用创建完整的list,可以节约大量空间,这种一边循环一边计算生成的机制,成为生成器。注意这和异步IO有关。

# 创建生成器有几种方法,方法1:只要把一个列表生成式的[]改成(),就创建了一个generator
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
# 可以通过next()访问下一个生成器中的值
>>> next(g)
0
>>> next(g)
1
# 上述做法非常的复杂,正确的方法是通过for循环,并且可以防止抛出错误,注意生成器是一个可迭代对象
>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)
... 
0
1
4

# 方法2:如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator,注意是这个函数变为了一个generator
# 理解:因为生成器的作用就是不直接写出结果,而是调用的时候才会使用,所以当我们调用next函数的时候我们会得到通过yield返回的一个返回值(yield相当于return)但是这个yield不会结束程序,起到的是存档的作用,当我们再次执行next函数的时候从这个yield的下一行语句出发开始继续执行,注意yield本身是不会输出信息,如果需要在控制台看到数据我们需要使用print(next(iterator))
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)
    
#但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
>>> g = fib(4)
>>> while True:
...     try:
...         x = next(g)
...         print('g:', x)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...
g: 1
g: 1
g: 2
g: 3
Generator return value: done

生成器都是Iterator对象,但listdictstr虽然是Iterable,却不是Iterator

listdictstrIterable变成Iterator可以使用iter()函数

你可能会问,为什么listdictstr等数据类型不是Iterator

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

12.函数本身也可以赋值给变量,即:变量可以指向函数。

​ 同时,函数名可以指向对象,当然非常不建议这么做,这样会导致无法使用这个函数。

13.高阶函数:把函数作为参数传入,函数式编程就是指这种高度抽象的编程范式。

​ 这个有啥用?已经用到了,在sort中就有key函数,可以传入自定义的排序方法。

# map/reduce
map(f, Iterable)
f 函数本身(一个参数)
Iterable 可迭代对象
作用: 把Iterable中的每个对象都进行f函数操作

reduce(f, Iterable)
f 函数本身(两个参数)
Iterable 可迭代对象
作用: 依次把Iterable中的参数两两进行f操作,例reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4)
# 栗子,把str转化成int
from functools import reduce
DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return DIGITS[s]
    return reduce(fn, map(char2num, s))

# filter
filter(f, Iterable)
f 函数本身(一个参数)
Iterable 可迭代对象
作用: 把Iterable中的每个对象都进行f函数比较,判断是否留下。注意到filter()函数返回的是一个Iterator,也就是一个惰性序列,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list# sorted
sorted(Iterable, key, reverse)
Iterable 可迭代对象
key 自定义排序方法,可以不写
reverse 反向排序,缺省为True
作用:这个用的很多,但是容易和list.sort搞混。详细区别下有。普通sorted()可以对list排序

# 返回函数!!!!!!易错点
把函数作为返回值,可以延迟执行,当调用对象时才会真正调用
返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
参考案例:https://www.liaoxuefeng.com/wiki/1016959663602400/1017434209254976
# 栗子
def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:ax = ax + n
        return ax
    return sum
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
>>> f()
25

14.装饰器

我们要增强某个函数的功能,但是不希望修改这个函数,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。 本质上,decorator就是一个返回函数的高阶函数 ,我们要借助Python的@语法,把decorator置于函数的定义处 。

# 栗子
def now():print('2015-3-25')
def log(func):
    # wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。
    # 函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。可以使用以下方式,这个
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
# 使用
@log
def now():print('2015-3-25')
# 相当于now = log(now)
>>> now()
call now():
2015-3-25

# 如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。
def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
# 使用,相当于now = log('execute')(now)
>>> now()
execute now():
2015-3-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值