iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >有哪些提高Python编码水平的小技巧
  • 546
分享到

有哪些提高Python编码水平的小技巧

2023-06-16 12:06:59 546人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

本篇内容介绍了“有哪些提高python编码水平的小技巧”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 分割序列常见的序列类型有列表、元组

本篇内容介绍了“有哪些提高python编码水平的小技巧”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

1. 分割序列

常见的序列类型有列表、元组和字符串。通过分割另一个序列,可以创建一个新序列。以下功能用列表作为示例,不过它们也可以用于元组、字符串和字节等其他序列类型。

>>> a = [0, 2, 4, 6, 8,10, 12, 14, 16, 18, 20] >>> # Using a range, [start, end) >>> a[1:3] [2, 4] >>> # Using a range with a step >>> a[1:9:2] [2, 6, 10, 14] >>> # Leave out the start = an implicit start of 0 >>> a[:5] [0, 2, 4, 6, 8] >>> # Leave out the stop = an implict end to the very last item >>> a[9:] [18, 20] >>> # Entire list >>> a[:] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

2. 使用反向索引访问序列中的元素

如果想在序列的末尾访问一些元素,那么反向计数要容易得多。在Python序列中,最后一个元素的索引是-1,倒数第二个元素的索引是-2,以此类推。

>>> a = 'Hello World!' >>> # instead of using a[len(a)-1] >>> a[-1] '!' >>> # in combination with slicing >>> a[-5:-1] 'orld'

3. 多重赋值

在给几个变量赋值时,可以使用多重赋值。通过同样的习惯用法,可以交换同一列表中的两个变量或两个元素。这一特征与之后要介绍的元组解包密切相关。

>>> # instead of doing a =8; b = 5 >>> a, b = 8, 5 >>> print(f'a is {a}; b is {b}') a is 8; b is 5 >>> # Swap two variables >>> a, bb = b, a >>> print(f'a is {a}; b is {b}') a is 5; b is 8 >>> # Swap the first and last elements in a list >>> numbers = [1, 2, 3, 4, 5] >>> numbers[0], numbers[-1] = numbers[-1], numbers[0] >>> numbers [5, 2, 3, 4, 1]

4. 颠倒序列

有时需要颠倒序列。虽然可以用for循环语句来实现,但是还有一种更简单直接的方法。与上述情况类似,当某个功能可用于某个序列时,通常意味着字符串、元组和列表也都支持这个功能。

>>> a = (1, 2, 3, 4, 5) >>> a[::-1] (5, 4, 3, 2, 1) >>> b = 'start' >>> b[::-1] 'trats'

5. 检查序列是否为空

只有序列不为空时,列表、元组等操作才行得通,因此需要在操作之前检查序列是否为空。

>>> empty_list = [(), '',[], {}, set()] >>> for item in empty_list: ...     if not item: ...         print(f'Do something with the{type(item)}') ... Do something with the <class 'tuple'> Do something with the <class 'str'> Do something with the <class 'list'> Do something with the <class 'dict'> Do something with the <class 'set'>

为此,可以用not关键字来否定序列(例如not[]),只要序列不为空,其值就为True。此外,还可以对另外两种常见的数据类型dict和set执行同样的操作。

6. 集合推导式

集合推导式的用法与上述列表解析式的用法类似。不同之处在于集合推导式用的是花括号而不是方括号。并且,通过定义set 数据类型,可以删除重复的元素。

7. 字典生成式

除了列表解析式和集合推导式外,解析式特征还可用于字典数据类型的创建。dict由键值对组成,因此字典生成式包含指定键和值,二者之间用冒号隔开。

>>> a = [1, 2, 3, 4, 5] >>> {x: x*x for x in a} {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

8. 生成器表达式

Python中的生成器是创建迭代器的一种简便方法。因为生成器是“惰性的”(也就是说,只有当发出请求时才能生成需要的项)。生成器非常节省内存。

创建生成器的一种特殊方法称为生成器表达式。除了用圆括号而非方括号这一点外,生成器表达式在语法上与列表解析式类似。

下面的例子中,当生成器直接用于迭代函数时,圆括号可有可无。

>>> sum(x**2 for x inrange(100)) 328350 >>> max((x*x for x in range(100))) 9801

9. 列表解析式

Python中一个有用的特征是列表解析式。通过列表解析式,可以很方便地构造一个列表。列表解析式的一般格式为[some_expression for  element initerable if some_condition]。

>>> a = [1, 2, 3, 4, 5] >>> [x*2 for x in a] [2, 4, 6, 8, 10] >>> [x*3 for x in a if x%2 == 1] [3, 9, 15]

10. 解包元组

元组是Python中十分常见的数据结构。它们是一组组相关的值。元组的常见用法包括访问自身元素。虽然可以使用索引访问这些元素,但是解包是一种更为简便的方法。

与解包的用法有关,可以用下划线来表示不需要的元素,用星号给已命名元素之外的其他元素赋值。

>>> items = (0, 'b','one', 10, 11, 'zero') >>> a, b, c, d, e, f = items >>> print(f) zero >>> a, *b, c = items >>> print(b) ['b', 'one', 10, 11] >>> *_, a, b = items >>> print(a) 11

11. 在for循环语句中使用Reversed()函数

reversed()函数通常用在for循环语句中,是一种以与原始可迭代对象相反的顺序创建迭代器的方法。

>>> tasks = ['laundry','picking up kids', 'gardening', 'cooking'] >>> for task in reversed(tasks): ... print(task) ... cooking gardening picking up kids laundry

12. Zip()压缩函数

zip()函数在一对一匹配连接多个迭代器方面十分有用。如果某些迭代器超过最短的迭代器,就会被截断。zip()函数返回一个迭代器,因此在迭代中经常使用到。还可以用zip()函数解压缩带星号的迭代器,并将未压缩的项赋值给变量。

>>> students = ('John','Mary', 'Mike') >>> ages = (15, 17, 16) >>> scores = (90, 88, 82, 17, 14) >>> for student, age, score in zip(students, ages, scores): ... print(f'{student}, age: {age},score: {score}') ... John, age: 15, score: 90 Mary, age: 17, score: 88 Mike, age: 16, score: 82 >>> zipzipped = zip(students, ages, scores) >>> a, b, c = zip(*zipped) >>> print(b) (15, 17, 16)

13. 用Lambdas排序

lambdas表达式为匿名函数,可以用单行表达式接收多个参数。lambdas的一个常见用法是将其设置为内置sorted()函数中的key参数。

除此之外,lambdas还经常用于max(),map()等函数中。在这些函数中,可以用单行表达式来替换使用def关键字的常规函数。

>>> students = [{'name':'John', 'score': 98}, {'name': 'Mike', 'score': 94}, {'name': 'Jennifer','score': 99}] >>> sorted(students, key=lambda x: x['score']) [{'name': 'Mike', 'score': 94}, {'name': 'John', 'score': 98}, {'name':'Jennifer', 'score': 99}]

14. 速记条件赋值

该特征基本上是个语法糖。在根据特定条件为变量赋值时,可以用以下通用速记赋值:y = x if condition_met  elseanother_x。

>>> some_condition = True >>> # the expanded fORMat >>> if some_condition: ... x = 5 ... else: ... x = 3 >>> print(f'x is {x}') x is 5 >>> # the shorthand way >>> x = 5 if some_condition else 3 >>> print(f'x is {x}') x is 5

15. 在for循环语句中使用Enumerate()枚举函数

用enumerate()函数获取可迭代对象来创建迭代器。此外,enumerate()函数还可以跟踪迭代的次数。可以随意设置计数初始值。默认的计数初始值为0。

>>> students = ('John','Mary', 'Mike') >>> for i, student in enumerate(students): ... print(f'Iteration: {i}, Student:{student}') ... Iteration: 0, Student: John Iteration: 1, Student: Mary Iteration: 2, Student: Mike >>> for i, student in enumerate(students, 35001): ... print(f'Student Name: {student},Student ID #: {i}') ... Student Name: John, Student ID #: 35001 Student Name: Mary, Student ID #: 35002 Student Name: Mike, Student ID #: 35003

16. 用Get()方法检索字典中的值

通常情况下,可以在方括号中指定键来检索键的值。但是,当键不在字典中时,就可能出错。当然,也可以用try/except异常处理机制来解决这个问题。不过,当键不在字典中时,还可以通过get()方法设置默认值。

>>> number_dict = {0:'zero', 1: 'one', 2: 'two', 3: 'three'} >>> number_dict[5] Traceback (most recent call last): File "<stdin>", line 1,in <module> KeyError: 5 >>> number_dict.get(5, 'five') 'five'

17. 获取字典中最大值对应的键

有时需要在字典中找出最大值对应的键。首先,在所有值列表中找到最大值的索引,然后从另一个存储所有键的列表中找到对应的键。或者,也可以用一种更简单的方法,就是在max()函数中指定key参数。

简便起见,不考虑最大值可能重复的情况。同样地,还可以用min()函数查找最小值对应的键。

>>> model_scores ={'model_a': 100, 'model_z': 198, 'model_t': 150} >>> # workaround >>> keys, values = list(model_scores.keys()),list(model_scores.values()) >>> keys[values.index(max(values))] 'model_z' >>> # one-line >>> max(model_scores, key=model_scores.get) 'model_z'

18. 用Print()函数进行调试

对于较小的项目,可以用print()函数进行调试。此函数也经常用在教学中。print()函数中,经常会用到一些技巧。第一个是结束字符串而不是默认的换行符;第二个是使用字符串f-string,创建包含一些表达式的字符串。

>>> for i in range(5): ... print(i, end=', ' if i < 4else '\n') ... 0, 1, 2, 3, 4 >>> for i in range(5): ... print(f'{i} & {i*i}', end=',' if i < 4 else '\n') ... 0 & 0, 1 & 1, 2 & 4, 3 & 9, 4 & 16

19. 集合元素存在性测试

有时,在对集合或匹配项进行操作之前,需要测试集合中是否存在某个元素。惯用的方法是使用关键字in。

>>> a = ('one', 'two','three', 'four', 'five') >>> if 'one' in a: ... print('The tuple contains one.') ... The tuple contains one. >>> b = {0: 'zero', 1: 'one', 2: 'two', 3: 'three'} >>> if 2 in b.keys(): ... print('The dict has the key of2.') ... The dict has the key of 2.

20. 海象运算符

海象运算符(:=)是Python 3.8版本中的新功能。它不过是赋值表达式(给表达式中的变量赋值)的另一个名称。

通常,当表达式使用变量时,变量声明须提前。使用海象运算符,变量赋值可以包含在表达式中,并且可以立即使用该变量。

>>> a = ['j', 'a', 'k','d', 'c'] >>> if (n := len(a))%2 == 1: ... print(f'The number of letters is{n}, which is odd.') ... The number of letters is 5, which is odd.

21. 分割字符串

在处理字符串时,通常要将字符串分隔成单词列表。这种情况下,可以使用split()函数的分隔符,并且可选最大分隔。相关的函数有rsplit()函数,和split()函数功能类似,只是在设置时从右侧开始分割,以满足最大分割要求。

>>> sentence = 'this is, apython, tutorial, about, idioms.' >>> sentence.split(', ') ['this is', 'a python', 'tutorial', 'about', 'idioms.'] >>> sentence.split(', ', 2) ['this is', 'a python', 'tutorial, about, idioms.'] >>> sentence.rsplit(', ') ['this is', 'a python', 'tutorial', 'about', 'idioms.'] >>> sentence.rsplit(', ', 2) ['this is, a python, tutorial', 'about', 'idioms.']

22. Map()映射函数

map()函数是个高阶函数(即使用函数作为参数或返回一个值作为其输出的函数)。其通用格式为map(function,  iterables)。map()函数将可迭代对象作为参数并返回一个map 对象,map 对象又是一个迭代器。可迭代对象的数量应与函数所需的参数数量匹配。

以下示例中,内置函数pow()需要两个参数。当然,也可以使用自定义函数。顺便说明一下,在使用map()函数创建列表时,应该可以使用列表解析式达到相同的效果。

>>> numbers = (1, 2, 4, 6) >>> indices = (2, 1, 0.5, 2) >>> # use map() >>> list(map(pow, numbers, indices)) [1, 2, 2.0, 36] >>> # list comprehensions >>> [pow(x, y) for x, y in zip(numbers, indices)] [1, 2, 2.0, 36]

23. Filter()过滤函数

filter()函数使用指定的函数或lambda函数过滤序列。该函数返回一个filter对象,filter对象是个迭代器。总的来说,该函数的用法与map()函数非常相似。

>>> def Good_word(x: str): ... has_vowels = not set('aeiou').isdisjoint(x.lower()) ... long_enough = len(x) > 7 ... good_start =x.lower().startswith('pre') ... return has_vowels &long_enough & good_start ... >>> Words = ['Good', 'Presentation', 'preschool', 'prefix'] >>> list(filter(good_word, words)) ['Presentation', 'preschool']

24. 连接可迭代对象中的字符串

在处理字符串时,有时需要通过连接列表、元组等可迭代对象内的一系列字符串来创建单个字符串。这种情况下,可以用所需分隔符调用的join()函数。

>>> words = ('Hello','Python', 'Programmers') >>> '!'.join(words) 'Hello!Python!Programmers' >>> words_dict = {0: 'zero', 1: 'one', 2: 'two', 3: 'three'} >>> '&'.join(words_dict.values()) 'zero&one&two&three'

25. 查找列表中最常见的元素

在用列表记录一些具有重复元素的内容时,例如跟踪一系列游戏的获胜者,这与查找哪位游戏玩家赢得的次数最多有关。可以通过  max()函数指定key参数,对集合中元素的计数来找出最大值。

>>> winnings = ['John','Billy', 'Billy', 'Sam', 'Billy', 'John'] >>> max(set(winnings), key = winnings.count) 'Billy'

26. 检验对象类型

检验对象类型是Python内省功能的一部分。有时,在应用对应函数之前,需要知道对象是否为某种类型。于是,可以用type()函数或isinstance()函数,后者更为灵活,可以进行一对多的检验。

>>> def check_type(number): ... if type(number) == int: ... print('do something with anint') ... if isinstance(number, (int,float)): ... print('do something with anint or float') ... >>> check_type(5) do something with an int do something with an int or float >>> check_type(4.2) do something with an int or float

27. Any() 函数

假设有一张记录列表,记录了John到达工作地点的时间。如果想知道他这周是否迟到过,那么用any()函数就十分方便。如果布尔型列表中有一个元素为True,则any()函数返回True。

>>> arrival_hours ={'Mon': 8.5, 'Tue': 8.75, 'Wed': 9, 'Thu': 8.5, 'Fri': 8.5} >>> arrival_checks = [x>8.75 for x in arrival_hours.values()] >>> any(arrival_checks) True

28. 跟踪列表中元素的频率

如果还想知道非冠军玩家在比赛中表现如何,根据上面的例子,就可以知道第二名和第三名玩家的情况。要想做到这一点,需要找出每位玩家的奖励。可以用字典生成式和带有lambda函数功能的sorted()函数。

>>> winnings = ['John','Billy', 'Billy', 'Sam', 'Billy', 'John'] >>> tracked = {item: winnings.count(item) for item in set(winnings)} >>> sorted(tracked.items(), key=lambda x: x[1], reverse=True) [('Billy', 3), ('John', 2), ('Sam', 1)]

29. 集体判断函数All()

还是用上面的例子,如果还想知道他一周内到达工作地点的时间是否都在9:30之前,就可以使用all()函数。只有布尔型列表中所有的元素均为True时,all()函数才返回True。

>>> arrival_checks_all =[x<9.5 for x in arrival_hours.values()] >>> all(arrival_checks) True

30. 用With关键字读取文件

处理文件时,需要打开文件,处理文件数据,然后关闭文件。如果在使用后没有关闭文件,过了一段时间后,就没法儿读取该文件。这种情况下,with  关键字非常有用。如下所示,使用后文件将自动关闭。

>>> withopen('a_file.txt') as file: ... pass ... >>> file.closed True

“有哪些提高Python编码水平的小技巧”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: 有哪些提高Python编码水平的小技巧

本文链接: https://www.lsjlt.com/news/283626.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 有哪些提高Python编码水平的小技巧
    本篇内容介绍了“有哪些提高Python编码水平的小技巧”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. 分割序列常见的序列类型有列表、元组...
    99+
    2023-06-16
  • 有哪些提高代码性能的编程小技巧
    这篇文章主要介绍“有哪些提高代码性能的编程小技巧”,在日常操作中,相信很多人在有哪些提高代码性能的编程小技巧问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”有哪些提高代码性能的编程小技巧”的疑惑有所帮助!接下来...
    99+
    2023-06-16
  • 有哪些Python高效代码小技巧
    本篇内容主要讲解“有哪些Python高效代码小技巧”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“有哪些Python高效代码小技巧”吧!把不常用的类别整合成一个有时你会得到元素分布不均的栏,少有的...
    99+
    2023-06-16
  • 提高效率的Java代码小技巧有哪些
    提高效率的Java代码小技巧有哪些,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。前言代码优化 ,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改...
    99+
    2023-06-16
  • 编写Python小技巧有哪些
    本篇内容主要讲解“编写Python小技巧有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“编写Python小技巧有哪些”吧!1. List:all_equal功能实现:检验一个列表中的所有元素...
    99+
    2023-06-16
  • 9个提高 Python 编程的小技巧
    目录01 交换变量02 字典推导和集合推导03 计数时使用Counter计数对象04 漂亮的打印出JSON05 解决FizzBuzz06 连接07 数值比较08 同时迭代两个列表09...
    99+
    2024-04-02
  • 提高代码性能的技巧有哪些
    这篇文章主要介绍“提高代码性能的技巧有哪些”,在日常操作中,相信很多人在提高代码性能的技巧有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”提高代码性能的技巧有哪些”的疑惑...
    99+
    2024-04-02
  • 编写JavaScript代码的小技巧有哪些
    小编给大家分享一下编写JavaScript代码的小技巧有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1 Array.inc...
    99+
    2024-04-02
  • 在任何IDE中提高编码速度的技巧有哪些
    这篇文章主要讲解了“在任何IDE中提高编码速度的技巧有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“在任何IDE中提高编码速度的技巧有哪些”吧!1.减少...
    99+
    2024-04-02
  • 有哪些Python编码常用技巧
    这篇文章主要介绍“有哪些Python编码常用技巧”,在日常操作中,相信很多人在有哪些Python编码常用技巧问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”有哪些Python编码常用技巧”的疑惑有所帮助!接下来...
    99+
    2023-06-16
  • 提高CSS代码效率的技巧有哪些
    本篇内容介绍了“提高CSS代码效率的技巧有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.注意外边距...
    99+
    2024-04-02
  • Python编程代码技巧有哪些
    本篇内容介绍了“Python编程代码技巧有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Python 提供了一组独特的工具和语言特性来使...
    99+
    2023-06-17
  • 加速Python编程的小技巧有哪些
    本篇内容主要讲解“加速Python编程的小技巧有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“加速Python编程的小技巧有哪些”吧!1.负索引人们喜欢使用序列,因为当我们知道元素的顺序,我...
    99+
    2023-06-15
  • 高效率的Python编程技巧有哪些
    这篇文章主要介绍“高效率的Python编程技巧有哪些”,在日常操作中,相信很多人在高效率的Python编程技巧有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”高效率的Python编程技巧有哪些”的疑惑有所...
    99+
    2023-06-16
  • 加快Python编程的小技巧有哪些
    这篇文章主要介绍“加快Python编程的小技巧有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“加快Python编程的小技巧有哪些”文章能帮助大家解决问题。1.负索引人们喜欢使用序列,因为当我们知...
    99+
    2023-06-27
  • div+css编程提醒及小技巧有哪些
    div+css编程提醒及小技巧有哪些,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。ul标签在Mozilla中默认是有padding值的,而在IE中只有margin有值。同一个的...
    99+
    2023-06-08
  • 有哪些Python小技巧
    这篇文章主要讲解了“有哪些Python小技巧”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“有哪些Python小技巧”吧!集合开发人员常常忘记 Python 也有集合数据类型,大家都喜欢使用列...
    99+
    2023-06-15
  • 用Python进行编码的技巧有哪些
    本篇内容主要讲解“用Python进行编码的技巧有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“用Python进行编码的技巧有哪些”吧!1. 可读性的重要性程序必须为了人们能够读懂而编写,其次...
    99+
    2023-06-16
  • 提高网页加载速度的小技巧有哪些
    这期内容当中小编将会给大家带来有关提高网页加载速度的小技巧有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。其次,关键字的排名与网页的打开速度也有关系(参考:影响关键字排名的重要因素),这个主要体现搜索...
    99+
    2023-06-08
  • Python源代码编制技巧有哪些
    本篇内容介绍了“Python源代码编制技巧有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!PyDev 就能显示出一个超链接,这样您可以在...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作