19. 第十九章拾珍

19. 拾珍

本书的一大目标一直是尽可能少的介绍Python语言.
如果做某种事情有两种方法, 我会选择一种, 并避免提及另一种.
或者有时候, 我会把另一种方法作为练习进行介绍.本章我会带领大家回顾那些遗漏的地方.
Python提供了不少并不是完全必需的功能(不用它们也能写出好代码),
但有时候, 使用这些功能可以写出更简洁, 更可读或更高效的代码, 甚至有时候三者兼得.
19.1 条件表达式
我们在5.4节中见过条件语句.
条件语句通常用来从两个值中选择一个. 例如:
if x > 0:y = math.log(x)
else:y = float('nan')
# 完整代码
import mathdef main(x):if x > 0:y = math.log(x)else:y = float('nan')return yif __name__ == '__main__':res = main(0)print(res, type(res))  # nan <class 'float'>
这条语句检查x是否为正数.
如果为整数, 则计算math.log; 如果为负数, math.log会抛出ValueError异常.
为了避免程序停止, 我们直接生成一个'NaN', 一个特殊的浮点数, 代表'不是数'(Not A Number).我们可以使用'条件表达式'来更简洁地写出这条语句:
y = math.log(x) if x > 0 else float('nan')
这条语句几乎可以用英语直接读出来'y gets log-x if x greater than 0; otherwise is gets NaN'
(y的值在大于0时时math.log(x), 否则是NaA).
递归函数有时候可以使用条件表达式重写.
例如, 下面是factorial的一个递归版本:
def factorial(n):if n == 0:return 1else:return n * factorial(n - 1)
我们可以将其重写为:
def factorial(n):return 1 if n == 0 else n * factorial(n - 1)
条件表达式的另一个用途是处理可选参数.
例如, 下面是GoodKangaroo的init方法(参见练习17-2):
def __init__(self, name, contents=None):self.name = name# 推荐使用is比较if contents == None:contents = []self.pouch_contents = contents
我们可以将其重写为:
def __init__(self, name, contents=None):self.name = nameself.pouch_contents = [] if contents == None else contents
一般来说, 如果条件语句的两个条件分支都包含简单的返回或对同一变量进行赋值的表达式,
那么这个语句可以转化为条件表达式.
19.2 列表理解
10.7节中我们已经见过映射和过滤模式. 例如, 下面的函数接收一个字符串列表, 
将每个元素通过字符串方法capitalize进行映射, 并返回一个新的字符串列表:
def capitalize_all(t):res = []for s in t:# 转为大写res.append(s.capitalize())return res
我们可以用列表理解(list comprehension)把这个函数写得更紧凑:
def capitalize_all(t):return [s.capitalize() for s in t]
上面的方法括号操作符说明我们要构建一个新的列表.
方括号之内的表达式指定了列表的元素, 而for子句则表示我们要遍历的序列.列表理解的语法有一点粗糙的地方, 因为里面的循环变量, 即本例中的s, 在表达式出现在定义之前.列表理解也可以用于过滤操作.
例如, 下面的函数选择列表t中的大写元素, 并返回一个新列表:
def only_upper(t):res = []for s in t:if s.isupper():res.append(s)return res
我们可以用列表理解将其重写为:
def only_upper(t)return [s for s in t if s.isupper()]
对于检查表达式来说, 列表理解更紧凑, 更易于阅读,
并且它们通常都比实现相同功能的循环更快, 有时候甚至快很多.
因此, 如果你因为我没有早些提到它而恼怒, 我表示十分理解.但是我们辩解一下, 列表理解更难以调试, 因为你没法再循环内添加打印语句.
我建议你只在计算简单到一次就能弄对的时候才使用它.
对初学者来说, 这意味着从来不用.
19.3 生成器表达式
生成器表达式(generator  expression) 和列表理解类似, 但是它使用圆括号, 而不是使用方括号:
>>> g = (x ** 2 for x in range(5))
>>> g
>>> <generator objrct <genexpr> at 0x7f4c5a786c0>
结果是一个生成器对象, 它知道该如何便遍历值的序列.
但它又和列表理解不同, 它不会一次把结果计算出来, 而是等待请求.
内置函数next会从生成器中获取下一个值:
>>> next(g)
0
>>> next(g)
1
当到达序列的结尾后, next会抛出一个StopIteration异常.
可以使用for循环来遍历所有值:
>>> for val in g:
...		print(val)
4
9
16
生成器对象会跟踪记录访问序列的位置, 所以for循环会从上一个next所在的位置继续.
一旦生成器遍历结束, 再访问它就会抛出StopException:
>>> next(g)
StopException
生成器表达式经常和sum, max, 和min之类的函数配合使用:
>>> sum(x ** 2 for x in range(5))
30
19.4 any和all
Python提供了一个内置函数any, 它接收一个由布尔值组成的序列, 并在其中任何(一个)值是True时返回True.
它可以用于列表:
>>> any([False, False, True])
>>> True
但它更常用于生成器表达式:
>>> any(letter == 't' for letter in 'monty')
True
上面这个例子用处不大, 因为它做的事情和in表达式一样.
但是我们可以用any来重写9.3节中的搜索函数.
例如, 我们可以将aviods函数重新为:
def avoids(word, forbidden):return not any(letter in forbidden for letter in word)
这个函数读起来几乎和英语一致:
'word avoids forbidden if there are not any forbidden letters in word'
(我们说一个word避免被禁止, 是指word中没有任何被禁的字母).
Python还提供了另一个内置函数all, 它在序列中所有元素都是True时返回True.
作为练习, 请使用all重写9.3节中的users_all函数.
# 字符串, 组成字符串的字母.
def user_all(word, required):# 从字母组中遍历字母for letter in required:# 判断字母是否在word中, 有一个字母不在, 则返回False.if letter not in word:return False# 全部存在则返回True.return Trueprint(user_all('hello', 'h'))  # True
# 重写
def user_all(word, required):return all(letter in word for letter in required)print(user_all('hello', 'h'))  # True
19.5 集合
我曾在13.6节中使用字典来寻找在文档中出现但不属于一个单词列表的单词.
我写的函数接收一个字典参数d1, 其中包含文档总所有的单词作为键; 以及另一个参数d2, 包含单词列表.
它返回一个字典, 包含d1中所有不在d2之中的键:
def substracr(d1, d2):res = dict()for key in d1:if key not in d2:res[key] = Nonereturn res
在这些字典中, 值都是None, 因为我们从来不用它们.
因此, 我们实际上浪费了一些存储空间.
Python还提供了另一个内置类型, 称为集合(set), 它表现得和没有值而使用键集合的字典类似.
向一个集合添加元素很快, 检查集合成员也很快. 集合还提供方法和操作符来进行常见的集合操作.例如, 几何减法可以使用方法difference或者操作符'-'来实现.
因此我们可以将substract函数重写为:
def substract(d1, d2):return set(d1) - set(d2)
结果是一个集合而不是字典, 但是对于遍历之类的操作, 表现是一样的.
本书中的一些练习可以使用集合来更加简洁且高效地实现.
例如, 练习10-7中的has_duplicates函数, 下面是使用字典来实现的一个解答:
def has_duplicates(t):d = {}for x in t:if x in d:return Trued[x] = Truereturn False
一个元素第一次出现的时候, 把它加入到字典中. 如果相同的元素再次出现时, 函数就返回True.
使用集合, 我们可以这样写同一个函数:
def has_duplicates(t):return len(set(t) < len(t))
一个元素在一个结合中只能出现异常, 所以如果t中间的某个元素出现超过一次, 那么变成集合后其长度比t小.
如果没有任何重复元素, 那么集合的长度应当和t相同.我们也可以使用集合来解决第9章中的一些练习.
例如, 下面是users_only函数使用循环来实现的版本:
def users_only(word, available):for letter in word:if letter not in available:return Falsereturn True
users_only检查word中所有的字符是不是在available中出现.
我们可以这样重写:
def users_only(word, available):return set(word) <= set(available)
操作符 <= 检查一个集合是否是零一个集合的子集, 包括两个集合相等的情况.
这正好符合word中所有字符都出现在Available中.
19.6 计数器
计数器(counter)和集合类似, 不同之处在于, 如果一个元素出现超过一次, 计数器会记录它出现了多少次.
如果你熟悉多重集(multiset)这个数学概念, 就会发现计数器是多重集的一个自然的表达方式.计数器定义在标准模块collections中, 所有需要导入它在使用.
可以用字符串, 列表或者其他任何之处迭代访问的类型对象来初始化计数器:
>>> from collections import Counter
>>> count = Counter('parrot')
>>> count
Counter({'r': 2, 't': 1, 'o': 1, 'p': 1, 'a': 1})
计数器有很多地方和字典相似. 它们将每个键映射到其出现次数. 和字典一样, 键必须是可散列的.
但和字典不同的是, 在访问计数器中不存在的元素时, 它并不会抛出异常, 相反, 它会返回0:
>>> count['d']
0
我们可以使用计数器来重写练习10-6中的is_anagram函数:
def is_anagram(word1, word2):return Counter(word1) == Counter(word2)
如果两个单词互为回文, 则它们会包含相同的字母, 且各个字母计数相同, 所有他们对应的计数器对象也会相等.
计数器提供方法和操作符来进行类似集合的操作, 包括集合加法, 减法, 并集和交集.
计数器还提供一个非常常用的方法most_common, 它返回一个'值-频率对'的列表, 
按照最常见到最少见来排序:
>>> count = Counter('parrot')
>>> for val, freq in count.most_common(3):
... 	print(val, freq)r 2
p 1
a 1
19.7 defaultdict
collections模块提供了defaultdict, 它和字典相似, 不同的是, 如果你访问一个不存在的键,
它会自动创建一个新值.创建一个defaultdict对象时, 需要提供一个用于创建新值的函数. 
用来创建对象的函数有时被称为'工厂(factory)'函数.
用于创建列表, 集合以及其他类型对象的内置函数, 都可以用作工厂函数:
>>> from collections import defaultdict
# 这里的list是工厂函数
>>> d = defaultdict(list)
请注意, 参数是list(一个类对象), 而不是list()(一个新的列表).
你提供的函数直到访问不存在的键时, 才会被调用的:
# t是一个别名
>>> t = d['new key']
# 访问不存在的键, 返回一个空列表.
>>> t
[]
新列表t也会加到字典中. 所有, 如果我们修改t, 改动也会在d中体现:
# 往空列表中追加值.
>>> t.append('new value')
>>> d
defaultdict(<class 'lsit'>, {'new key': ['new value']})
如果创建一个由列表组成的字典, 使用defaultdict往往能够帮你写出更简洁的代码.
在练习12-2的解答中, 我创建了一个字典, 将排序的字母字符串映射到可以由那些字母拼写的单词列表.
例如, 'opst'映射到列表['opst', 'pots', 'spot', 'stop', 'tops'].
可以从↓下载该解答.
https://github.com/AllenDowney/ThinkPython2/blob/master/code/anagram_sets.py
下面是原始的代码:
def all_anagrams(filename):# 创建字典d = {}# 遍历文件对象的每一行for line in open(filename):# 每一行按去除首尾空白字符(包含\n换行符), 最后转为小写字母.word = line.strip().lorwe()# 对单词按字母排序(升序), 返回一个排序后的单词.t = signature(word)# 单词不在字典中则新建项(排序后的单词, [排序前的单词1, 排序前的单词2, ...])if t not in d:d[t] = [word]else: d[t].append(word)# 返回字典return ddef signature(s):t = list(s)t.sort()t = ''.join(t)return t
这个函数(all_anagrams)可以用setdefault简化, 你可能在练习11-2中也用过:
def all_anagrams1(filename):d = {}for line in open(filename):word = line.strip().lower()t = signature(word)d.setdefault(t, []).append(word)return d
但这个解决方案有一个缺点, 它不管是否需要, 每次都会新建一个列表.
(因为列表被作为参数传到进去了, 传递给setdefault方法, 所有每次调用都要创建.)
我们可以使用defaultdict来避免这个问题, 并进一步简化代码:
def all_anagrams(filename):d = defaultdict(list)for line in open(filename):t = signature(word)d[t].append(word)return d
在练习18-3的解答中, 函数has_straightflush中使用了setdefault.
可以从↓下载它.
https://github.com/AllenDowney/ThinkPython2/blob/master/code/PokerHandSoln.py
但这个解决方法的缺点是, 不管是否必需, 每次循环迭代都会创建一个新的Hand对象.
作为练习, 请使用dedaultdict重写该函数.
from collections import defaultdict# 在PokerHand类中def has_straightflush(self):# 工厂函数d = defaultdict(PokerHand)# 遍历卡牌for c in self.cards:# 往字典中保存项, (键为花色, 值为一个列表) PokerHand()得到一个扑克手对象,d[c.suit].add_card(c)  # add_card将卡牌添加到列表中.# 遍历字典的值, 值时一个列表for hand in d.values():# 花色列表的值小于5则跳过if len(hand.cards) < 5:continue# 5张卡片的花色相同, 使用直方图统计, 花色和大小.hand.make_histograms()# 判断是否有顺子, 如果有则返回Trueif hand.has_straight():return Truereturn False
19.8 命名元组
很多简单的对象其实都可以看作是几个相关值的集合.
例如, 15章中定义的Point对象, 包含两个数字, 即x和y.
定义一个这样的类时, 通常会从init方法和str方法开始.
class Point:def __init__(self, x=0, y=0):self.x = xself.y = ydef __str__(self):return '(%g, %g)' % (self.x, self.y)
这里用来更多代码来传达很少的信息.
Python提供了一个更简单的方式来表达用一个意思:
from collections import namedetuple
Point = namedtuple('Point', ['x', 'y'])
第一个参数是你想要创建的类名.
第二个参数是Point对象应当包含的属性的列表, 以字符串表示.
namedtuple的返回值是一个类对象:
>>> Point
<class '__main__.Point'>
这里Point类会自动提供__init__和__str__这样的方法, 所以你不需要写它们.
要创建一个Point对象, 可以把Point类当作函数来用:
>>> p = Point(1, 2)
>>> p
Point(x=1, y=2)
init方法使用你提供的名字把实参赋值给属性.
str方法会打印出Point对象及其属性的字符串表示.可以使用名称来访问命名元组的元素:
>>> p.x, p.y
(1, 2)
也可以直接把它当作元组来处理:
>>> p[0], p[1]
(1, 2)
>>> x, y = p
>>> x, y
(1, 2)
命名元组还提供了快速定义简单类的方法, 但其缺点是简单的类并不会总保持简单.
可能之后你需要给命名元组条件方法. 如果定义一个新类, 继承当前的命名元组:
class Pointier(Point):# 在这里添加更多的方法
或者也可以直接切换成传统的类定义.
19.9 收集关键词参数
12.4节中, 我们见过如何编写函数将其参数收集成一个元组:
def printall(*args):print(args)
可以使用任意个数的按位实参(也就是说, 不带名称的实参)来调用这个函数:
>>> printall(1, 2.0, '3')
(1, 2.0, '3')
但是*号操作符并不会收集关键字实参:
>>> printall(1, 2.0, third='3')
...
TypeError: printall() got an unecpected keyword argument 'third'
要收集关键词实参, 可以使用**操作符:
def printall(*args, **kwargs): print(args, kwargs)
这里收集关键字形参可以任意命名, 但kwargs是一个常见的选择.
收集的结果是一个将关键词映射到值的字典:
>>> printall(1, 2.0, third='3')
(1, 2.0) {'third': ''}
如果有一个关键词到值的字典, 就可以使用分散操作符**来调用函数:
>>> d = dict(x=1, y=2)
>>> Point(**d)
Point(x=1, y=2)
没有用分散操作符的话, 函数会把d当作一个单独的按位实参, 所有它会把d赋值给x, 并因为没有提供y的赋值而报错:
>>> d = dict(x=1, y=2)
>>> Point(d)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeEroor: __new__() missing 1 required positional argument: 'y'
当处理参数很多的函数时, 创建和传递字典来指定常用的选项是非常有用的.
19.10 术语表
条件表达式(conditional expression): 一个根据条件返回一个或两个值的表达式.列表理解(list comprehension): 一个以方框包含一个for循环, 生成新列表的表达式.生成器表达式(generator ecpression): 一个以括号包含一个for循环, 返回一个生成器对象的表达式.多重集(multiset): 一个用来表达从一个集合的元素到它们出现次数的映射的数学概念.工厂函数(factory): 一个用来创建对象, 并常常当作参数使用的函数.
19.11 练习
1. 练习1
下面的函数可以递归地计算二项式系数:
def binomial_coeff(n, k):"""计算(n, k)的二项式系数,n: 实验次数k: 成功次数返回: int"""if k == 0:return 1if n == 0:return 0res = binomial_coeff(n-1, k) + binomial_coeff(n-1, k-1)return res
使用内嵌条件表达式来重写该函数.
注意: 这个函数频率不高, 因为它会不停得重复计算相同的值.
可以通过使用备忘(memoizing, 参见11.6)来提高它的效率.
但你可能会发现, 使用条件表达式之后, 添加备忘会变得比较困难.
def binomial_coeff(n, k):""" 计算(n, k)的二项式系数, n: 实验次数 k: 成功次数 返回: int """ return 1 if k == 0 else 0 if n == 0 else binomial_coeff(n-1, k) + binomial_coeff(n-1, k-1)
memo_k = {}def binomial_coeff0(n, k):if k == 0:return 1if n == 0:return 0res = binomial_coeff0(n - 1, k) + binomial_coeff0(n - 1, k - 1)return resdef binomial_coeff1(n, k):key = n, kres = 1 if k == 0 else 0 if n == 0 else \binomial_coeff1(n - 1, k) + binomial_coeff1(n - 1, k - 1)memo_k[key] = resreturn resdef binomial_coeff2(n, k):return 1 if k == 0 else 0 if n == 0 else \binomial_coeff2(n - 1, k) + binomial_coeff2(n - 1, k - 1)def main(n, k):res0 = binomial_coeff0(n, k)print(res0)res1 = binomial_coeff1(n, k)print(res1)res2 = binomial_coeff2(n, k)print(res2)if __name__ == '__main__':main(7, 2)

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

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

相关文章

Vue 3 中的状态管理:使用 reactive 函数实现组件间通信和状态管理

在 Vue 3 中&#xff0c;使用 reactive 函数可以创建一个响应式对象&#xff0c;从而实现夸组件间的通信和状态管理。可以将 reactive 函数创建的状态管理单独放在一个 JavaScript 文件中&#xff0c;以实现更好的代码组织和复用。具体步骤如下&#xff1a; 创建一个新的 JavaS…

泛型复习(java)

文章目录 泛型为什么用泛型泛型特性泛型的擦出和补偿自定义泛型在类上自定义泛型在方法上使用泛型在接口上定义泛型 类型通配符 泛型 为什么用泛型 不用泛型 public class User {public static void main(String[] args) {//创建 arraylist 集合Collection arraylist new A…

利用Cesium和JS实现地点点聚合功能

引言 在实现基于地图的业务场景时&#xff0c;当地图上需要展示过多的标记点时&#xff0c;大量的分散点会使地图上显得杂乱无章&#xff0c;导致标记点对地图上的其他重要信息造成遮挡和混淆&#xff0c;降低地图整体的可读性。 标记点的聚合就很好的解决了这些痛点的同时&a…

[大模型]XVERSE-MoE-A4.2B Transformers 部署调用

XVERSE-MoE-A4.2B介绍 XVERSE-MoE-A4.2B 是由深圳元象科技自主研发的支持多语言的大语言模型&#xff08;Large Language Model&#xff09;&#xff0c;使用混合专家模型&#xff08;MoE&#xff0c;Mixture-of-experts&#xff09;架构&#xff0c;模型的总参数规模为 258 亿…

apt-get update和apt-get upgrade的区别

apt-get update apt-get update 命令用于更新本地软件包列表。具体来说&#xff0c;做了以下事情&#xff1a; ①从 /etc/apt/sources.list 文件和 /etc/apt/sources.list.d/ 目录下的所有文件中读取软件源配置。 ②连接到这些软件源&#xff0c;并下载最新的软件包列表。 ③将…

springcloud入门与实践

Spring Cloud 是一个基于 Spring Boot 的框架&#xff0c;专注于微服务架构下的常见问题&#xff0c;如服务发现、负载均衡、断路器、分布式配置、消息驱动的微服务等。以下是 Spring Cloud 的入门指南和实践示例。 1. 环境准备 首先&#xff0c;确保你已经安装了以下工具&am…

Python 潮流周刊#56:NumPy 2.0 里更快速的字符串函数

△△请给“Python猫”加星标 &#xff0c;以免错过文章推送 本周刊由 Python猫 出品&#xff0c;精心筛选国内外的 250 信息源&#xff0c;为你挑选最值得分享的文章、教程、开源项目、软件工具、播客和视频、热门话题等内容。愿景&#xff1a;帮助所有读者精进 Python 技术&am…

Mysql(一):深入理解Mysql索引底层数据结构与算法

众所众知&#xff0c;MySql的查询效率以及查询方式&#xff0c;基本上和索引息息相关&#xff0c;所以&#xff0c;我们一定要对MySql的索引有一个具体到数据底层上的认知。 这一次也是借着整理的机会&#xff0c;和大家一起重新复习一下MySql的索引底层。 本节也主要有一下的…

AOSP : Android编译记录

Android编译记录 1、关注编译配置文件2、编译记录2.1 设置构建环境2.2 记录 1、关注编译配置文件 Android.bp 或 Android.mk Android.bp 文件格式 2、编译记录 2.1 设置构建环境 source build/envsetup.sh lunch product_name-release-build_variant查看当前的启动设置&#…

【PL理论】(25) C- 语言:表达式求值的推理规则 | 执行语句的推理规则 | 语句执行的推理规则

&#x1f4ad; 写在前面&#xff1a;本章我们将继续更新我们的 "C-" 语言&#xff0c;更新表达式求值的推理规则、执行语句的推理规则以及语句执行的推理规则。 目录 0x00 C- 语言更新&#xff1a;表达式求值的推理规则 0x01 C- 语言更新&#xff1a;执行语句的推…

网页五子棋对战项目测试(selenium+Junit5)

目录 网页五子棋对战项目介绍 网页五子棋对战测试的思维导图​ 网页五子棋对战的UI自动化测试 测试一&#xff1a;测试注册界面 测试二&#xff1a;测试登陆界面 测试三&#xff1a;测试游戏大厅界面 测试四&#xff1a;测试游戏房间界面以及观战房间界面 测试五&#…

【技巧】Leetcode 67. 二进制求和【简单】

二进制求和 给你两个二进制字符串 a 和 b &#xff0c;以二进制字符串的形式返回它们的和。 示例 1&#xff1a; 输入:a “11”, b “1” 输出&#xff1a;“100” 示例 2&#xff1a; 输入&#xff1a;a “1010”, b “1011” 输出&#xff1a;“10101” 解题思路 …

软考-架构设计师-综合知识总结(试卷:2009~2022)(下篇)

说明 本文档对2009到2022年试卷的综合知识进行了归纳总结&#xff0c;同时对叶宏主编的《系统架构设计师教程》划分重点。 第十七章&#xff1a;通信系统架构设计 17.2 考题总结 第十八章&#xff1a;安全架构设计 18.1 重要知识点 18.2 考题总结 第十九章&#xff1a;大数据…

传统后端SQL数据层替代解决方案: 内置数据源+JdbcTemplate+H2数据库 详解

内置数据源 我们回顾一下druid数据源的配置方式 通过type属性指定数据源的类型 导入依赖 starter就使用了spring的自动装配功能 格式二是在引入druid的依赖的基础上 进行的一种配置方式 Tomcat内部也可以进行数据源的配置 轻量级中最快的数据源对象 我们切换德鲁伊连接池 我…

OpenDevin 环境配置及踩坑指南

不惧怕任何环境配置 首先 clone 项目&#xff0c;然后查看开发者文档&#xff1a;https://github.com/OpenDevin/OpenDevin/blob/main/Development.md make setup-config 自定义 LLM 配置 首先这个 devin 写的是支持自定义的 LLM 配置&#xff0c;并且提供了交互式命令供我们…

DzzOffice集成功能最丰富的开源PHP+MySQL办公系统套件

DzzOffice是一套开源办公套件&#xff0c;旨在为企业和团队提供类似“Google企业应用套件”和“微软Office365”的协同办公平台。以下是对DzzOffice的详细介绍&#xff1a; 主要功能和应用&#xff1a; 网盘&#xff1a;支持企业、团队文件的集中管理&#xff0c;提供文件标签…

app-ios 内嵌h5的缓存问题

在iOS应用中内嵌H5页面时&#xff0c;可能会遇到缓存问题&#xff0c;导致页面更新不及时。以下是一些解决策略和方法&#xff1a; 目录 方法1&#xff1a;Nginx配置 方法2&#xff1a;使用版本号 方法1&#xff1a;Nginx配置 通过Nginx服务器配置来控制缓存行为。例如&#…

Python开发示例——使用Python实现炫酷的数据动态图

前言 数据可视化是通过图形、图表、地图等可视元素将数据呈现出来&#xff0c;以便更容易理解、分析和解释。它是将抽象的数据转化为直观形象的过程&#xff0c;有助于发现数据中的模式、趋势和关系。数据可视化对于数据科学、商业分析、决策制定等领域都至关重要。当我们想用…

UniApp+Vue3使用Vant-微信小程序组件

第一步&#xff1a;打开创建好的UniappVue3的项目 第二步&#xff1a;下载Vant-Weapp npm i vant/weapp -S --production 第三步&#xff1a;修改目录名称 wxcomponents 必须是wxcomponents 第四步&#xff1a;将下载好的vant中的dist目录剪切到当前wxcomponents目录下 第五…

在 Linux 上刷新 DNS 缓存:告别过时解析,提升网络访问效率

引言 在 Linux 系统中&#xff0c;DNS&#xff08;域名系统&#xff09;缓存对于提高网络访问速度和效率至关重要。然而&#xff0c;当 DNS 记录发生更改或需要更新时&#xff0c;旧的缓存条目可能会导致访问问题或连接到错误的服务器。因此&#xff0c;了解如何在 Linux 上刷…