函数的定义和调用
函数用于对代码逻辑的封装和隔离,在 Python 和 JavaScript 中,函数都被视作一等公民。
任务
编写一个打招呼的函数,将传入的个人信息(姓名、年龄、性别)格式化后打印。
JavaScript 实现
javascript
function greet(name, age, gender='保密') {
console.log(`你好,我是${name},今年${age}岁,性别${gender}`)
}
console.log(greet('张三', 18));
console.log(greet('李四', 18, '男'));
console.log(greet(...['王五', 18, '女']));
Python 实现
python
def greet(name, age, gender='保密'):
print(f"你好,我是{name},今年{age}岁,性别{gender}")
print(greet('张三', 18)) # 传入位置参数
print(greet(age=18,name='张三')) # 传入关键字参数
print(greet('李四', 18, '男'))
print(greet(*['王五', 18, '女']))
代码解读
- Python 使用
def
关键字定义函数,JavaScript 使用function
关键字定义函数。 - Python 使用冒号
:
和缩进表示函数体,JavaScript 使用花括号表示函数体。 - Python 中,除默认值参数之外(如上面的
gender
参数),函数的每个参数都是必传的,否则会出现语法错误。而在 JavaScript 中未传递的参数默认值为undefined
。 - 在 Python 中,按照顺序传入的参数叫做 位置参数 ,必须严格按照形参定义顺序传入。此外,还可以使用
key=value
的形式向函数传入关键字参数,关键字参数的顺序不必与形参顺序保持一致,位置参数和关键字参数可以一起使用,但 必须保证调用函数时提供了所有必要参数 。 - Python 中,可以使用
my_fn(*[p1, p2, ...])
的形式传入位置参数,与 JavaScript 中的myFn(...[p1, p2, ...])
类似。
差异速览
特性 | JavaScript | Python |
---|---|---|
函数定义 | function myFn(params) { ... } |
def my_fn(params): |
函数调用 | myFn(params) |
my_fn(params) |
:::tip 如何获取函数入参? 使用 *args
获取传入的全部位置参数,类型为元组。使用 **kwargs
获取传入的全部关键字参数,类型为字典。
css
def some_fn(position_arg, *args, **kwargs):
print(position_arg)
print(args)
print(kwargs)
some_fn('position_arg_value','add_to_args1','add_to_args2',a=1,b=2,c=3)
# 运行结果
# position_arg_value
# ('add_to_args1', 'add_to_args2')
# {'a': 1, 'b': 2, 'c': 3}
类似地,Python 也可以使用 **
展开一个字典
python
def some_fn(a, b, c):
print(a, b, c) # 1 2 3
my_dict = {"c": 3, "b": 2, "a": 1} # Python 对字典中键的顺序没有要求
some_fn(**my_dict)
*args
和 **kwargs
虽然方便,但如果函数只定义了这两个形参,IDE 将失去代码提示,同时函数的逻辑也将变得难以理解,需要谨慎使用。 :::
相关资源
匿名函数
当需要一个可以在不定义单独函数的情况下内联执行的小段代码时,可以使用匿名函数,在 Python 中,匿名函数称为 "lambda 表达式" 或 "lambda 函数"。
任务
使用匿名函数,将数字列表的每一项映射为它的平方并打印新列表。
JavaScript 实现
javascript
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map(number => number ** 2);
console.log(squaredNumbers);
Python 实现
python
numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(lambda number: number ** 2, numbers))
print(squared_numbers)
代码解读
- Python 使用
lambda
关键字创建匿名函数,JavaScript 使用function
或=>
创建匿名函数。 - Python 的
lambda
函数不能包含函数体,表达式的值将作为返回值自动返回。而 JavaScript 中的匿名函数可以有函数体和 return 语句。
差异速览
特性 | JavaScript | Python |
---|---|---|
创建匿名函数 | (params) => expression |
lambda params: expression |
:::tip 当 Python 的 lambda 函数有多个参数时,使用 ,
隔开每一个参数。 :::
相关资源
创建和导入模块
一个庞大的应用程序通常由许多模块构成,模块在软件开发中是代码组织的独立单元,每一个 .py
文件都是一个 Python 模块,每一个 .js
文件都是一个 JavaScript 模块。
任务
设计一个程序,定义一个计算器模块,提供加减乘除四则运算功能。在另一个模块中引入该模块,计算并打印 1234 * 4321
的结果。
JavaScript 实现
javascript
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export function multiply(a, b) {
return a * b;
}
export function divide(a, b) {
if (b === 0) {
throw new Error("除数不能为0");
}
return a / b;
}
javascript
import { multiply } from './calculator.js';
console.log(multiply(1234, 4321));
Python 实现
python
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ValueError("除数不能为0")
return a / b
python
import calculator
result = calculator.multiply(1234, 4321)
print(result)
代码解读
- Python 和 JavaScript 都使用
import
关键字导入模块。 - Python 模块成员不需要使用
export
关键字进行导出,模块中全部成员都将自动导出。
:::danger Python 模块中的私有成员 在 Python 中,所有在模块内可以访问的变量、函数、类等都是自动导出的,可以被其他模块任意引用,Python 没有提供保护模块私有成员的方法。若模块中的某些成员不希望被其他模块导入,可以按照约定,使用 _
或 __
开头对成员进行命名。同时,在使用第三方模块时,我们也要遵守这个约定,不要直接导入和使用以下划线开头的成员。 :::
差异速览
特性 | JavaScript | Python |
---|---|---|
导入模块 | import foo from 'module' |
import foo |
从模块导入特定成员 | import { foo, bar } from 'module' |
from module import foo, bar |
将模块导入为别名 | import { foo as alias } from 'module' |
from module import foo as alias |
将整个模块导入为别名 | import * as alias from 'module' |
import module as alias |
默认导出 | export default module |
- |
命名导出 | export foo |
- |
:::tip Python 中的模块名称由文件名决定,文件名称不能包含 -
,否则无法被其他模块引用。
Python 在文件名与模块名之间存在一些转换约定如下:
文件名 | 模块名 | 说明 |
---|---|---|
my_module.py | my_module | 模块名与文件保持一致 |
myModule.py | mymodule | 大写字母自动转换为小写 |
:::
相关资源
创建和导入包
在 Python 中,包是一个包含多个 Python 模块的目录。Python 中的包和模块的概念类似于使用目录和文件在 JavaScript 中组织和结构化代码,但略有不同。
假设有一个名为 "my_package" 的文件夹(在 Python 中称之为包),它包含了许多文件和文件夹:
markdown
my_package/
__init__.py
module1.py
module2.py
subpackage/
__init__.py
module3.py
横过来是这样:
markdown
my_package
/ \
module1.py module2.py subpackage
/ \
module3.py (其他模块)
首先,"my_package" 是一个文件夹,它里面有一个名为 "init.py" 的文件,它是一个特殊的文件,用户编写一些初始化包的代码,该文件是可选的。
在 "my_package" 包中,还有 "module1.py" 和 "module2.py" 两个模块,它们是编写变量、函数、类的定义的地方。
此外,还有一个名为 "subpackage" 的文件夹,它是一个子包。和 "my_package" 一样。
在 "subpackage" 子包中,有一个名为 "module3.py" 的模块。这个模块同样包含了一些变量、函数、类的定义,但它是在 "subpackage" 这个特定的上下文中使用的。
现在,可以在应用程序的任一模块中,从包中导入想要的模块
python
import my_package.subpackage # 当不指定模块名称时,默认导入 __init__.py 中的成员,与 JavaScript 项目中的 index.js 文件作用类似
from my_package.subpackage.module3 import my_function # 从 module3.py 中的导入 my_function
如上,由包和模块的搭配,让代码形成了 "命名空间" 。
:::tip 许多 JavaScript 工程师刚接触 Python 包相关的知识时,可能还会遇到代码中的包导入时报 搜索路径相关错误 的问题,可通过 官方文档 中的说明解决。 :::
相关资源
本书的内容完全免费,开源地址:github.com/luckrnx09/p...