2025-09-10:仓库迁移
This commit is contained in:
16
7.函数/1.编写可接受任意数量参数的函数.py
Normal file
16
7.函数/1.编写可接受任意数量参数的函数.py
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
|
||||
# 要编写一个接受任意数量参数的函数,可以使用*
|
||||
def avg(first, *rest):
|
||||
return (first + sum(rest))/(len(rest) + 1)
|
||||
|
||||
# 如果是关键字类型的参数,那就需要使用**
|
||||
def make_element(name, value, **attrs):
|
||||
for item in attrs.items():
|
||||
print("'{} = {}'".format(*item))
|
||||
return 0
|
||||
|
||||
# *与**有使用上的限制,它们必须在所有参数的最后,**必须在*后面
|
||||
def anyargs(*args, **kwargs):
|
||||
print(args)
|
||||
print(kwargs)
|
24
7.函数/10.1.补课,协程.py
Normal file
24
7.函数/10.1.补课,协程.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# 这里我们要介绍一下协程的机制,协程是在单个线程内让两个函数交替执行的一种形式
|
||||
# 以著名问题生产者和消费者作为基底进行讨论
|
||||
def consumer():
|
||||
return_str = ''
|
||||
while True:
|
||||
print(1)
|
||||
n = yield return_str
|
||||
if not n:
|
||||
return
|
||||
print("消费者正在消费{}".format(n))
|
||||
return_str = "200 OK"
|
||||
|
||||
def producer(c):
|
||||
next(c)
|
||||
n = 0
|
||||
while n < 5:
|
||||
n = n + 1
|
||||
print("生产者正在生产{}".format(n))
|
||||
return_str = c.send(n)
|
||||
print("消费者收到消息返回{}".format(return_str))
|
||||
c.close()
|
||||
|
||||
con = consumer()
|
||||
producer(con)
|
43
7.函数/10.在回调函数中携带额外的状态.py
Normal file
43
7.函数/10.在回调函数中携带额外的状态.py
Normal file
@@ -0,0 +1,43 @@
|
||||
def apply_async(func, args, *, callback):
|
||||
result = func(*args)
|
||||
callback(result)
|
||||
|
||||
def print_result(result):
|
||||
print(result)
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
# 如果只是简单的调用回调函数,那直接用就可以了
|
||||
apply_async(add, (1, 2), callback=print_result)
|
||||
apply_async(add, ('hello', 'world'), callback=print_result)
|
||||
|
||||
# 但是,如果我想要知道这个函数被调用了几次,携带这些保存的信息返回,可以这样改写:
|
||||
def make_handler():
|
||||
sequence = 0
|
||||
def handler(result):
|
||||
nonlocal sequence
|
||||
sequence += 1
|
||||
print('[{}] Got: {}'.format(sequence, result))
|
||||
return handler
|
||||
handler = make_handler()
|
||||
apply_async(add, (1, 2), callback=handler)
|
||||
apply_async(add, (1, 2), callback=handler)
|
||||
|
||||
|
||||
# 当然我们也能用协程去搞定它:
|
||||
# 协程的复习在10.1中,单步调试你就看懂了
|
||||
def make_handler_v2():
|
||||
sequence = 0
|
||||
while True:
|
||||
result = yield
|
||||
sequence += 1
|
||||
print('[{}] Got: {}'.format(sequence, result))
|
||||
handler = make_handler_v2()
|
||||
next(handler)
|
||||
apply_async(add, (1, 2), callback=handler.send)
|
||||
apply_async(add, (1, 2), callback=handler.send)
|
||||
apply_async(add, (1, 2), callback=handler.send)
|
||||
|
||||
|
||||
|
48
7.函数/11.内联回调函数.py
Normal file
48
7.函数/11.内联回调函数.py
Normal file
@@ -0,0 +1,48 @@
|
||||
# 如果我们像上一节一样写一堆小函数在代码里,相信我你很快就会暴毙
|
||||
# 我们希望我们的内敛回调看起来比较正常
|
||||
# 我们有这样一个函数来调用回调:
|
||||
def apply_async(func, args, *, callback):
|
||||
result = func(*args)
|
||||
callback(result)
|
||||
|
||||
from queue import Queue
|
||||
from functools import wraps
|
||||
|
||||
class Async:
|
||||
def __init__(self, func, args):
|
||||
self.func = func
|
||||
self.args = args
|
||||
|
||||
def inline_async(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args):
|
||||
f = func(*args)
|
||||
result_queue = Queue()
|
||||
result_queue.put(None)
|
||||
while True:
|
||||
result = result_queue.get()
|
||||
try:
|
||||
a = f.send(result)
|
||||
apply_async(a.func, a.args, callback=f.send)
|
||||
except StopIteration:
|
||||
break
|
||||
return wrapper
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
@inline_async
|
||||
def test():
|
||||
r = yield Async(add, (2, 3))
|
||||
print(r)
|
||||
r = yield Async(add, ('hello', 'world'))
|
||||
print(r)
|
||||
for n in range(5):
|
||||
r = yield Async(add, (n, n))
|
||||
print(r)
|
||||
print("Bye")
|
||||
|
||||
|
||||
# 这个东西比较高级,一般不使用这种方法,会让代码可读性变差
|
||||
# 拒绝个人炫技,回归可读本质,从你我做起
|
||||
test()
|
69
7.函数/12.访问定义在闭包内的变量.py
Normal file
69
7.函数/12.访问定义在闭包内的变量.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# 我们有时候可以用函数来拓展闭包,使闭包获得类似类的效果
|
||||
def sample():
|
||||
n = 0
|
||||
|
||||
def func():
|
||||
print("n=", n)
|
||||
|
||||
def get_n():
|
||||
return n
|
||||
|
||||
def set_n(value):
|
||||
# nonlocal让我们可以访问闭包内的变量,有点类似类里的self
|
||||
nonlocal n
|
||||
n = value
|
||||
# 我们能这么做的本质原因还是因为Python里的万物皆类特性
|
||||
func.get_n = get_n
|
||||
func.set_n = set_n
|
||||
return func
|
||||
|
||||
|
||||
f = sample()
|
||||
f()
|
||||
# 可以看到这里并没有出现代码提示,因为基类没有包含这些东西,它们是在动态编译的时候加入的
|
||||
f.set_n(10)
|
||||
f()
|
||||
f.get_n()
|
||||
|
||||
import sys
|
||||
# 比如下面有个类
|
||||
class ClosureInstance:
|
||||
def __init__(self, locals=None):
|
||||
if locals is None:
|
||||
locals = sys._getframe(1).f_locals
|
||||
self.__dict__.update((key, value) for key, value in locals.items() if callable(value))
|
||||
|
||||
def __len__(self):
|
||||
return self.__dict__['__len__']()
|
||||
|
||||
# 这是用这个类实现的栈实例
|
||||
def Stack():
|
||||
items = []
|
||||
|
||||
def push(item):
|
||||
items.append(item)
|
||||
|
||||
def pop():
|
||||
items.pop()
|
||||
|
||||
def __len__():
|
||||
return len(items)
|
||||
|
||||
return ClosureInstance()
|
||||
|
||||
# 这是正常的写法
|
||||
class Stack2:
|
||||
def __init__(self):
|
||||
self.items = []
|
||||
|
||||
def push(self, item):
|
||||
self.items.append(item)
|
||||
|
||||
def pop(self):
|
||||
return self.items.pop()
|
||||
|
||||
def __len__(self):
|
||||
return len(self.items)
|
||||
|
||||
# 从执行来说,闭包的写法比正常写法块8%,因为不需要访问额外的self变量
|
||||
# 不!要!这!么!做!除非有非得这样干的理由,否则别这样搞,老老实实写类,这样的闭包只有类的功能而没有继承多态这些类属性
|
13
7.函数/2.编写只接受关键字参数的函数.py
Normal file
13
7.函数/2.编写只接受关键字参数的函数.py
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
# 在*参数和**参数之间,可以加入普通参数,这种普通参数被称为keyword_only参数
|
||||
def recv(maxsize, *, block):
|
||||
print("recv msg")
|
||||
pass
|
||||
|
||||
# 这类参数只能被指定输入,示例如下:
|
||||
recv(1024, True) # 报错TypeError
|
||||
recv(1024, block=True) # 正确
|
||||
|
||||
|
||||
|
5
7.函数/3.将元数据信息附加到函数参数上.py
Normal file
5
7.函数/3.将元数据信息附加到函数参数上.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# 有时候我们会想要将函数参数加上类型提示来方便其他人快速熟悉函数,那么可以这样做:
|
||||
|
||||
def test_function(x:int, y:int)->int:
|
||||
x = x**2
|
||||
return x+y
|
6
7.函数/4.从函数中返回多个值.py
Normal file
6
7.函数/4.从函数中返回多个值.py
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
# 如果需要从函数中返回多个值,只需要返回一个元组即可
|
||||
def fun():
|
||||
return 1, 2, 3
|
||||
|
||||
a, b, c = fun()
|
37
7.函数/5.定义带有默认参数的函数.py
Normal file
37
7.函数/5.定义带有默认参数的函数.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# 定义函数时,如果想要传入可选的参数,可以给参数加上默认值
|
||||
def span(a, b=42):
|
||||
print(a, b)
|
||||
|
||||
span(1)
|
||||
span(1, 2)
|
||||
|
||||
# 如果给参数指定默认值为None,那么该参数就可以传入可变容器
|
||||
def span_v2(a, b=None):
|
||||
print(a, b)
|
||||
span_v2(1, [1, 2])
|
||||
|
||||
# 但是如果你不想设置一个默认值,如果b没有传入参数那就提示,那么你需要给一个obj
|
||||
_no_value = object()
|
||||
def span_v3(a, b=_no_value):
|
||||
if b is _no_value:
|
||||
print("no b")
|
||||
|
||||
span_v3(1)
|
||||
|
||||
# 注意,函数的默认参数只会在函数首次被调用的时候绑定一次,函数第一次被调用后默认参数就不可变了
|
||||
x = 3
|
||||
def su_ka(a = x):
|
||||
print(a)
|
||||
su_ka(1)
|
||||
x = 4
|
||||
su_ka()
|
||||
|
||||
# 不要用【】这种地址型数据做默认参数,因为它真的可以在过程中被修改
|
||||
x = []
|
||||
def su_ka(a = x):
|
||||
print(a)
|
||||
su_ka()
|
||||
x.append(1)
|
||||
su_ka()
|
||||
|
||||
# 上面使用object作为空参数传入也有这方面的考量,因为用户的输入是不可预知的,而obj几乎不可能被用户创建
|
8
7.函数/6.定义匿名或内联函数.py
Normal file
8
7.函数/6.定义匿名或内联函数.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# 如果我们需要一个短小精悍的函数,那么lambda函数是唯一的选择
|
||||
|
||||
add = lambda x, y: x + y
|
||||
print(add(2,3))
|
||||
|
||||
# 就比如在sort函数里
|
||||
names = ["David Beazley", "Brain Jones", "Raymond Hettinger", "Ned Batchelder"]
|
||||
print(sorted(names, key=lambda name: name.split()[-1].lower()))
|
30
7.函数/7.在匿名函数中绑定变量的值.py
Normal file
30
7.函数/7.在匿名函数中绑定变量的值.py
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# lambda函数中的变量如果被赋值了是可以动态修改的,只要在每次调用之前修改,就能实现变化
|
||||
x = 1
|
||||
a = lambda y: x + y
|
||||
print(a(10))
|
||||
x = x + 9
|
||||
print(a(10))
|
||||
|
||||
x = x + 10
|
||||
print(a(10))
|
||||
|
||||
|
||||
# 如果你希望和正常函数一样在定义的时候绑死变量的值,那么你需要这样做
|
||||
b = lambda y, t=x: t + y
|
||||
print(b(10))
|
||||
x = x-1
|
||||
print(b(10))
|
||||
|
||||
# 比如有个比较聪明的函数
|
||||
func = [lambda x : x + n for n in range(5)]
|
||||
for f in func:
|
||||
print(f(0))
|
||||
|
||||
func2 = [lambda x, n=n: x + n for n in range(5)]
|
||||
for f in func2:
|
||||
print(f(0))
|
||||
|
31
7.函数/8.让有n个参数的可调用对象以较少的参数被调用.py
Normal file
31
7.函数/8.让有n个参数的可调用对象以较少的参数被调用.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import math
|
||||
from functools import partial
|
||||
|
||||
|
||||
# 假设我们有这样一个函数
|
||||
def spam(a, b, c, d):
|
||||
print(a, b, c, d)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 这个函数的输入参数有一大堆,但是其中几个是固定的,那就有用了
|
||||
s1 = partial(spam, 1) #固定a=1
|
||||
s2 = partial(spam, d=2) # 固定d=2
|
||||
s3 = partial(spam, 3, 3, d=3) # 固定a=3 b=3 d=3
|
||||
|
||||
s1(2,3,4)
|
||||
s2(1,2,3)
|
||||
s3(1)
|
||||
|
||||
# partial返回的是一个被填充了部分参数的函数,参数数量等于被包装的函数的剩余参数个数
|
||||
|
||||
# 这个函数可以用来适配一些参数数量受限的复用场景, 比如sorted函数的key参数仅支持单参数函数
|
||||
points = [(1, 2), (3, 4), (5, 6), (7, 8)]
|
||||
|
||||
def dis (p1, p2):
|
||||
x1, y1 = p1
|
||||
x2, y2 = p2
|
||||
return math.hypot(x2-x1, y2-y1)
|
||||
|
||||
pt = (4, 3)
|
||||
s = partial(dis, pt)
|
||||
print(sorted(points, key=s))
|
16
7.函数/9.用函数替代只有单个方法的类.py
Normal file
16
7.函数/9.用函数替代只有单个方法的类.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from urllib.request import urlopen
|
||||
|
||||
class UrlTemplate:
|
||||
def __init__(self, template):
|
||||
self.template = template
|
||||
|
||||
def open(self, **kwargs):
|
||||
return urlopen(self.template.format_map(kwargs))
|
||||
|
||||
# 对于这个类,我们可以使用闭包来进行重写
|
||||
def url_template(template):
|
||||
def opener(**kwargs):
|
||||
|
||||
return urlopen(template.format_map(kwargs))
|
||||
return opener
|
||||
|
Reference in New Issue
Block a user