Python:求求按规范写我

news2024/12/25 14:29:57

B站|公众号:啥都会一点的研究生

写在前面

代码被阅读的次数远多于编写的次数

我们可能花费很多时间来编写一段代码,一旦完成后大概率就再不会重新写它。当这段代码不仅是自己用时,就得注意了,每次自己或其他人浏览,需要快速知道它的作用及编写它的原因,因此可读性显得很重要,比如

>>> a = "Cai Xukun"
>>> b, c = a.split()
>>> print(b, c, sep=', ')

看到这种脑阔痛。那么,每个人都有自己的编码风格,如何使整个团队趋于一致呢?Python PEP 8早已考虑到这种情况

https://peps.python.org/pep-0008/

我们可能互相不清楚每个人的风格,但又必须阅读与理解各自产出的代码,那么此时遵循PEP 8会是最佳选择,也是每个Python从业者需要学习掌握的规范,一起看看吧

命名规范

编写代码时需要命名很多东西,如变量、函数、类等。选择合理的名称将节省以后的时间和精力,确保能够从名称中得到某个变量或函数代表的意义,不恰当的名称还会徒增调试难度

Tip:切勿使用 l 、 O 或 I 单字母名称,因为这些名称可能会被误认为 1 和 0

命名风格

以下是一些常见的命名约定以及如何使用示例,除了在代码中选择正确的命名样式之外,还必须仔细选择名称

类型命名约定例子
Variable使用小写的单个字母、单词或单词,用下划线分隔单词x, var, my_variable
Function使用一个或多个小写单词,用下划线分隔单词function, my_function
Class每个单词都以大写字母开头,这种风格称为驼峰式命名法或帕斯卡式命名法Model, MyClass
Method使用一个或多个小写单词,用下划线分隔单词class_method, method
Constant使用大写的单个字母、单词或单词,用下划线分隔单词CONSTANT, MY_CONSTANT, MY_LONG_CONSTANT
Module使用简短的小写单词,用下划线分隔单词module.py, my_module.py
Package使用简短的小写单词,不要用下划线分隔单词package, mypackage
如何选择名字

在编写代码时对命名选择需要进行足够的思考,在Python中为对象命名的最佳方法是使用描述性的名称

在命名变量时,可能会选择简单的、单个字母的小写名称。比如这篇文章开头的引例,要将一个人的姓名存储为字符串,并且想要使用字符串切片来以不同的方式格式化姓名吗,写成如下形式是不是更舒服?

>>> name = 'Cai Xukun'
>>> first_name, last_name = name.split()
>>> print(last_name, first_name, sep=', ')

同样地,为了偷懒,你可能在选择名称时使用缩写。如下示例中,定义了一个名为db()的函数,它接受一个参数x并将其乘2倍,乍一看,这似乎是一个明智的选择,db()是double的缩写,但在一段时间后再回到这段代码,可能已经忘记了这个函数实现什么,并为偷懒付出相应代价

def db(x):
    return x * 2

以下写法则要清晰得多

def multiply_by_two(x):
    return x * 2

相同的原则也适用于Python中所有其他数据类型和对象,始终尽量使用最简洁且具有描述性的名称总不会出错

代码排版布局

垂直空白,即空行,对于提升代码的可读性起着关键作用。密集堆叠的代码可能令人感到压抑,不易理解,同样地,代码中过多的空行则会让其看起来过于稀疏,带来不必要的滚动

将顶层函数和类用两个空行隔开。顶层函数和类通常相对独立,承担不同的功能。因此,为其周围添加适量的垂直空间是合理的,这有助于清晰地标示它们的独立性

class MyFirstClass:
    pass


class MySecondClass:
    pass


def top_level_function():
    return None

一个空行分隔类内方法定义

class MyClass:
    def first_method(self):
        return None

    def second_method(self):
        return None

在函数内部使用空行以展示清晰的步骤。有时,一个复杂的函数在return之前需要完成多个步骤。为了帮助读者理解函数内部的逻辑,每个步骤之间留出一个空行会很有帮助

在下面的示例中,有一个计算列表方差的函数。这是一个两步问题,通过在它们之间留出空行来表示每个步骤。在return之前也有一个空行,有助于清楚地看到返回了什么内容

def calculate_variance(number_list):
    sum_list = 0
    for number in number_list:
        sum_list = sum_list + number
    mean = sum_list / len(number_list)

    sum_squares = 0
    for number in number_list:
        sum_squares = sum_squares + number**2
    mean_squares = sum_squares / len(number_list)

    return mean_squares - mean**2
最大行长度和换行

PEP 8建议将行限制在79个字符以内,但很多时候将语句限制在79个字符或更少并不总是可能的。PEP 8概述了语句跨越多行的方法

如果代码包含在括号、方括号或花括号内,Python会假定它是行的延续

def function(arg_one, arg_two,
             arg_three, arg_four):
    return arg_one

还可以使用反斜杠来换行

from mypkg import example1, \
    example2, example3

如果需要在二元操作符(如+和)周围进行换行,应该在操作符之前进行*。这个规则源自数学,数学家们一致认为,在二元操作符之前换行可以提高可读性,可以立即看到正在相加或相减的变量,因为操作符紧邻正在操作的变量

total = (first_variable
         + second_variable
         - third_variable)

现在,让我们看一个在二元操作符之后换行的示例

total = (first_variable +
         second_variable -
         third_variable)

在这里,很难看出正在相加的变量和正在相减的变量

在二元操作符之前换行会产生更可读的代码,因此PEP 8鼓励这样做

缩进

缩进在Python中非常重要。在Python中,代码行的缩进级别决定了语句如何分组在一起

考虑以下示例:

x = 3
if x > 5:
    print('x is larger than 5')

缩进的打印语句告诉Python只有在if语句返回True时才执行它。相同的缩进规则适用于在调用函数时告诉Python要执行哪些代码,或者哪些代码属于给定的类

PEP 8规定的关键缩进规则如下:

  • 使用4个连续的空格来表示缩进
  • 优先选择空格而不是制表符
制表符 vs. 空格

如上所述,在缩进代码时应该使用空格而不是制表符。当按下Tab键时,可以调整文本编辑器的设置,将制表符字符输出为4个空格

Python 3不允许混合使用制表符和空格。如果正在使用Python 3,则会抛出这些错误

$ python3 code.py
  File "code.py", line 3
    print(i, j)
              ^
TabError: inconsistent use of tabs and spaces in indentation

可以使用制表符或空格来指示缩进的Python代码。但是,如果使用的是Python 3,必须在选择上保持一致,否则,代码将无法运行

换行后的缩进

当使用行延续将行保持在79个字符以下时,使用缩进来提高可读性非常有用。帮助区分两行代码和跨越两行的单行代码。可以使用两种缩进样式,第一种是将缩进块与起始分隔符对齐

def function(arg_one, arg_two,
             arg_three, arg_four):
    return arg_one

有时,只需要4个空格与起始分隔符对齐。这通常发生在跨多行的if语句中,因为if、空格和起始括号共计4个字符。在这种情况下,很难确定if语句内部的嵌套代码块从哪里开始

x = 5
if (x > 3 and
    x < 10):
    print(x)

在这种情况下,PEP 8提供了两种改进可读性的替代方法:

  • 在最终条件之后添加注释。由于大多数编辑器中的语法高亮,这将把条件与嵌套代码分开:
x = 5
if (x > 3 and
    x < 10):
    # Both conditions satisfied
    print(x)
  • 在行延续上添加额外的缩进
x = 5
if (x > 3 and
        x < 10):
    print(x)

换行后的另一种缩进样式是悬挂缩进,悬挂缩进即段落或语句中除了第一行外的每一行都缩进。可以使用悬挂缩进来在视觉上表示代码行的延续

var = function(
    arg_one, arg_two,
    arg_three, arg_four)

当使用悬挂缩进时,第一行不得有任何参数。

使用悬挂缩进时,添加额外的缩进以区分连续的行与函数内部的代码。如以下示例很难阅读,因为函数内部代码与连续的行处于相同的缩进级别:

def function(
    arg_one, arg_two,
    arg_three, arg_four):
    return arg_one

相反,最好在行延续上使用双重缩进。这有助于区分函数参数和函数体,提高可读性

def function(
        arg_one, arg_two,
        arg_three, arg_four):
    return arg_one
右括号怎么处理

行延续允许在括号、方括号或大括号内换行。但很容易忽略闭合括号的位置,将它放在合适的地方很重要。PEP 8提供了两个选项来确定隐式行延续中闭合括号的位置

  • 将闭合括号与前一行的第一个非空白字符对齐
list_of_numbers = [
    1, 2, 3,
    4, 5, 6,
    7, 8, 9
    ]
  • 将闭合括号与开始构造的行的第一个字符对齐
list_of_numbers = [
    1, 2, 3,
    4, 5, 6,
    7, 8, 9
]

可以自由选择使用哪个选项,但请保持一致

注释

使用注释来记录代码的编写以便自己和任何合作者都能理解。在添加注释到代码时,请记住以下要点:

  • 将注释和文档字符串的行长度限制在72个字符以内
  • 使用完整的句子,以大写字母开头。
  • 确保在更改代码时更新注释
块注释

块注释非常有用,帮助他人理解给定代码块的目的和功能,PEP 8为编写块注释提供以下规则

  • 将块注释的缩进与它们描述的代码保持一致
  • 每行以#开头,后跟一个空格
  • 使用只包含一个#的行来分隔段落

以下是解释for循环功能的块注释示例。为保持79字符行限制,句子被换行

for i in range(0, 10):
    # Loop over i ten times and print out the value of i, followed by a
    # new line character
    print(i, '\n')

有时,如果代码技术含量高,那么在块注释中使用多个段落是必要的

def quadratic(a, b, c, x):
    # Calculate the solution to a quadratic equation using the quadratic
    # formula.
    #
    # There are always two solutions to a quadratic equation, x_1 and x_2.
    x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
    x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)
    return x_1, x_2

如果不确定哪种注释类型适合,通常可以选择使用块注释

行内注释

行内注释用于解释代码片段中的单个语句。以下是PEP 8关于行内注释的建议

  • 适度使用行内注释
  • 将行内注释写在与其引用的语句同一行上
  • 将行内注释与语句之间用两个或更多空格分隔开
  • 与块注释一样,以#和一个空格开头
  • 不要用它们来解释显而易见的事情

以下是行内注释的示例

x = 5  # This is an inline comment

有时,行内注释是必要的,但可以使用更好的命名约定来替代

x = 'John Smith'  # Student Name

在这个示例中,行内注释确实提供了额外的信息。但是,将“x”作为人名的变量名是很呆的做法,如果更改变量名称,就不需要行内注释

student_name = 'John Smith'

最后,诸如以下的行内注释是不好的习惯(脱裤子放P),因为陈述了显而易见的事实并且会使代码混乱

empty_list = []  # Initialize empty list

x = 5
x = x * 5  # Multiply x by 5
文档字符串

文档字符串,docstrings,是出现在任何函数、类、方法或模块的第一行的双引号(“”")或单引号(‘’')括起来的字符串。用于解释和记录特定的代码块。PEP 257有专门阐述docstrings,docstrings最重要规则如下

  • 在docstrings两侧使用三个双引号,如 “”“这是一个docstring”“”

  • 为所有公共模块、函数、类和方法编写docstrings

  • 将终止多行docstring的"""单独放在一行上

def quadratic(a, b, c, x):
    """Solve quadratic equation via the quadratic formula.

    A quadratic equation has the following form:
    ax**2 + bx + c = 0

    There always two solutions to a quadratic equation: x_1 & x_2.
    """
    x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
    x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)

    return x_1, x_2
  • 对于单行docstrings,请将"""保持在同一行上
def quadratic(a, b, c, x):
    """Use the quadratic formula"""
    x_1 = (- b+(b**2-4*a*c)**(1/2)) / (2*a)
    x_2 = (- b-(b**2-4*a*c)**(1/2)) / (2*a)

    return x_1, x_2

表达式中的空格

在表达式和语句中适当使用空格可以非常有助于阅读。如果没有足够的空格,代码可能会难以阅读,因为它们都挤在一起。如果空格过多,则在语句中可能很难在视觉上组合相关术语

二元操作符周围的空格

在以下二元操作符的两侧都加上单个空格

  • 赋值操作符(=,+=,-=等)

  • 比较(==,!=,>,<,>=,<=)和(is,is not,in,not in)

  • 布尔运算(and,not,or)

Tip:当使用 = 为函数参数分配默认值时,不要用空格
如:
def function(default_parameter=5):

当语句中有多个操作符时,在每个操作符前后都添加单个空格可能会显得混乱。相反,最好只在具有最低优先级的操作符周围添加空格,特别是在进行数学操作时。以下是几个示例

# Recommended
y = x**2 + 5
z = (x+y) * (x-y)

# Not Recommended
y = x ** 2 + 5
z = (x + y) * (x - y)

还可以将此应用于具有多个条件的if语句

# Not recommended
if x > 5 and x % 2 == 0:
    print('x is larger than 5 and divisible by 2!')

在上面的示例中,and操作符具有最低优先级。因此,以下方式可能更清晰地表示

# Recommended
if x>5 and x%2==0:
    print('x is larger than 5 and divisible by 2!')

可以自由选择哪种更清晰,但请注意,操作符两侧必须使用相同数量的空格

在切片中,冒号充当二元操作符。因此,适用于前一节中概述的规则,两侧应具有相同数量的空格

list[3:4]

# Treat the colon as the operator with lowest priority
list[x+1 : x+2]

# In an extended slice, both colons must be
# surrounded by the same amount of whitespace
list[3:4:5]
list[x+1 : x+2 : x+3]

# The space is omitted if a slice parameter is omitted
list[x+1 : x+2 :]
何时避免添加空格

在某些情况下,添加空格可能会使代码更难阅读。PEP 8明确提供了一些不适合使用空格的示例。

最容易出Bug的是在行末,即尾随空格。因为它是不可见的,可能会产生难以追踪的错误

以下概述了一些应避免添加空格的情况:

  • 紧跟在括号、方括号或花括号内
# Recommended
my_list = [1, 2, 3]

# Not recommended
my_list = [ 1, 2, 3, ]
  • 在逗号、分号或冒号之前
# Recommended
print(x, y)

# Not recommended
print(x , y)
  • 在函数参数列表左括号之前
def double(x):
    return x * 2

# Recommended
double(3)

# Not recommended
double (3)
  • 在索引或切片的左括号之前
# Recommended
list[3]

# Not recommended
list [3]
  • 在尾随逗号和闭合括号之间
# Recommended
tuple = (1,)

# Not recommended
tuple = (1, )
  • 用于对齐赋值操作符
# Recommended
var1 = 5
var2 = 6
some_long_var = 7

# Not recommended
var1          = 5
var2          = 6
some_long_var = 7

编程建议

不要使用等价运算符将布尔值与True|False进行比较

# Not recommended
my_bool = 6 > 5
if my_bool == True:
    return '6 is bigger than 5'

在这里使用等价运算符(==)是不必要的,bool只能取True或False的值,以下写法已足够,PEP 8鼓励使用它

# Recommended
if my_bool:
    return '6 is bigger than 5'

如果要检查列表是否为空,首先会想要检查列表的长度,如果列表为空,它的长度为0,在if语句中使用时等效于False

# Not recommended
my_list = []
if not len(my_list):
    print('List is empty!')

然而,在Python中,任何空列表、字符串或元组都是False。因此,可以找到一个更简单的替代方案

# Recommended
my_list = []
if not my_list:
    print('List is empty!')

虽然这两个示例都会输出"List is empty!",PEP 8鼓励使用第二个方式

在if语句中,使用"is not"而不是"not … is"

# Recommended
if x is not None:
    return 'x exists!'

不要写成以下形式

# Not recommended
if not x is None:
    return 'x exists!'

在检查字符串是否以特定词开头或结尾时,使用.startswith().endswith()而不是切片

# Not recommended
if word[:3] == 'cat':
    print('The word starts with "cat"')

使用.startswith()

# Recommended
if word.startswith('cat'):
    print('The word starts with "cat"')

同样的原则也适用于检查后缀

# Recommended
if file_name.endswith('jpg'):
    print('The file is a JPEG')

以上就是本期的全部内容,如果想了解更多关于PEP 8的细节可以访问

https://pep8.org/

别忘了点赞再看哈,我是啥都生,下期再见

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

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

相关文章

2023.9.23(对这一年过去几个月的总结)

这个时间点杭州正在开亚运会&#xff0c;周六&#xff0c;大周&#xff0c;难得的大周&#xff0c;早上在公司健身房跑完步&#xff0c;就来工位看书了。 反思一下&#xff1a; 技术&#xff1a; 今年在技术学习上的目标&#xff0c;达成率是在太低&#xff0c;但看文章输出来…

tcp/ip协议2实现的插图,数据结构

&#xff08;1&#xff09;以上是插图第2章和3章 的 mbuf 与 ifnet 与 ifaddr 与 le_softc 与 sockaddr_dl结构体 谢谢

生信技巧 | GNU 并行操作

简介 有些分析需要很长时间&#xff0c;因为它在单个处理器上运行并且有大量数据需要处理。如果数据可以分成块并单独处理&#xff0c;那么问题就被认为是可并行化的。 数据并行情况 当文件的每一行都可以单独处理时 基因组的每条染色体都可以单独处理 组件的每个脚手架都可以单…

安全学习_开发相关_JavaEE过滤器监听器简单了解

文章目录 Web应用运行流程图 JavaEE-过滤器-Filter过滤器概述&作用过滤器相关安全测试场景 JavaEE-监听器-Listener监听器作用&#xff1a;监听器相关安全测试场景 过滤器和监听器&#xff0c;主要对安全测试有影响的是过滤器&#xff0c;监听器只是在对代码进行逻辑分析时…

【数学计算】使用mathematica计算圆周率π

【数学计算】使用mathematica计算圆周率 计算π的意义如何通过函数表示圆函数几何图形 计算圆周率 计算π的意义 在我们计算圆面积时&#xff0c;通常需要知道面积和已知变量之间的共性关系&#xff0c;以便能够将圆面积计算进行理论研究&#xff0c;以推广到所有的圆面积、周…

Golang代码漏洞扫描工具介绍——trivy

Golang代码漏洞扫描工具介绍——trivy Golang作为一款近年来最火热的服务端语言之一&#xff0c;深受广大程序员的喜爱&#xff0c;笔者最近也在用&#xff0c;特别是高并发的场景下&#xff0c;golang易用性的优势十分明显&#xff0c;但笔者这次想要介绍的并不是golang本身&a…

JMeter之脚本录制

【软件测试面试突击班】如何逼自己一周刷完软件测试八股文教程&#xff0c;刷完面试就稳了&#xff0c;你也可以当高薪软件测试工程师&#xff08;自动化测试&#xff09; 前言&#xff1a; 对于一些JMeter初学者来说&#xff0c;录制脚本可能是最容易掌握的技能之一。…

C/C++开发,opencv阀值操作

目录 一、OpenCV-阀值操作 1.1阀值操作函数threshold 1.2threshold的操作类型 1.3Otsu算法 二、样例开发 2.1 Makefile 2.2 main.cpp 2.3 运行效果 三、OpenCV-自适应阀值操作 3.1 自适应阀值操作函数-adaptiveThreshold 3.2 样例开发 一、OpenCV-阀值操作 1.1阀值操…

渗透测试中的前端调试(上)

一、前言 前端调试是安全测试的重要组成部分。它能够帮助我们掌握网页的运行原理&#xff0c;包括js脚本的逻辑、加解密的方法、网络请求的参数等。利用这些信息&#xff0c;我们就可以更准确地发现网站的漏洞&#xff0c;制定出有效的攻击策略。前端知识对于安全来说&#xff…

私域运营丨用户运营SOP,批量成交私域新老客户!

私域运营的重点内容除了社群外&#xff0c;还包括1对1的沟通成交。特别是针对价格高、决策成本高、需要定制化和深度服务、具有私密性的产品&#xff0c;非常适合进行1对1的成交。 通过建立标准化的用户运营SOP&#xff0c;可以更科学地管理私域客户&#xff0c;并根据客户所处…

AO天鹰优化算法|含源码(元启发式算法)|跑23个经典函数(含源码)

-------往期目录------ 1、灰狼优化算法 文章目录 天鹰优化器一、第一种搜索方法二、第二种搜素方法三、第三种搜素方法四、第四种搜索方法 代码实现 天鹰优化器 Aquila Optimizer&#xff08;AO&#xff09;&#xff0c;灵感来自Aquila在捕捉猎物过程中的自然界行为。因此&a…

华为云云耀云服务器L实例评测|云耀云服务器L实例部署HertzBeat实时监控系统

华为云云耀云服务器L实例评测&#xff5c;云耀云服务器L实例部署HertzBeat实时监控系统 一、云耀云服务器L实例介绍1.1 云耀云服务器L实例简介1.2 云耀云服务器L实例特点 二、HertzBeat介绍2.1 HertzBeat简介2.2 HertzBeat特点 三、本次实践介绍3.1 本次实践简介3.2 本次环境规…

Activiti7工作流 二【Activiti7入门、Activiti7进阶】

文章目录 六、Activiti7入门6.1 业务流程建模6.1.1 绘制流程图6.1.2 指定任务负责人6.1.3 生成png格式流程图 6.2 部署流程定义6.3 启动流程实例6.4 任务查询6.5 任务处理6.6 添加审批意见6.6 查看历史审批 七、Activiti7进阶7.1 流程定义相关7.1.1 流程定义查询7.1.2 流程资源…

基于Spring Boot的体育馆管理系统的设计与实现

目录 前言 一、技术栈 二、系统功能介绍 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 本基于Spring Boot的海滨体育馆管理系统设计目标是实现海滨体育馆的信息化管理&#xff0c;提高管理效率&#xff0c;使得海滨体育馆管理工作规范化、高效化。 本文重…

fonts什么文件夹可以删除吗?fonts文件夹删除了怎么恢复

在电脑上&#xff0c;fonts文件夹是存放字体文件的目录之一。尽管有时可能考虑删除该文件夹以节省硬盘空间或出于其他原因&#xff0c;但删除该文件夹可能会导致系统字体问题&#xff0c;影响用户的正常使用。因此&#xff0c;在删除之前需要考虑是否可以删除fonts文件夹&#…

golang优先级坑

看如下代码&#xff0c;我本以为a1, a2是相同的 package mainimport "fmt"func main() {b, c, d : 1, 0, 1a1 : b ^ c&(^d) // 1 ^a2 : c ^ b&(^d) // 0 ^fmt.Println(a1, a2) // 1 0 }但结果却是不同的&#xff0c;在golang中&的优先级^和&#xff5c;…

Edge 浏览器『版本回退』和『关闭更新』

前言 最近 Edge 浏览器又更新了&#xff0c;给整体浏览器页面布局进行大改动&#xff0c;之前苗条的标签页和收藏夹栏瞬间变得臃肿了&#xff0c;我实在无法忍受这种布局&#xff0c;所以我索性直接进行版本回退和设置永久关闭更新&#xff0c;详细步骤请看下文 Edge 浏览器版…

【新版】系统架构设计师 - 案例分析 - 架构设计<架构风格和质量属性>

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 架构设计&#xff1c;架构风格和质量属性&#xff1e;例题1例题2例题3例题4例题5例题6 架构 - 案例分析 - 架构设计&#xff1c;架构风格和质量属性&#xff1e; 例题1 某软件公司为…

大数据开发工程师面试题

一、选择题 1、哪个程序负责HDFS数据存储&#xff1f; Datanode 2、HDFS中的block默认保存几份&#xff1f; 默认3份 3、哪个程序通常与NameNode在一个节点启动&#xff1f; Jobtracker 4、HDFS默认Block Size是多少&#xff1f; 64MB 5、什么通常是集群的最主要瓶颈 …

typedef与define定义类型

#define _CRT_SECURE_NO_WARNINGS #define DataType2 int* #include<iostream> typedef int* DataType1; int main() {DataType1 a, b;DataType2 c, d;printf("%d %d %d %d", sizeof(a), sizeof(b), sizeof(c), sizeof(d));return 0; } 输出结果如何&#xf…