也有提供此功能的社区包,例如Click和 。
的函数
函数(也称为匿名函数)是没有名称且只有一个表达式作为其主体的小型函数。
在中,它们是使用关键字定义的:
lambda :
主体必须是单个表达式,而不是语句。
这很重要:表达式返回值,语句不返回。
最简单的函数示例是将数字的值加倍:
lambda num : num * 2
函数可以接受更多参数:
lambda a, b : a * b
无法直接调用函数,但您可以将它们分配给变量:
multiply = lambda a, b : a * b
print(multiply(2, 2)) # 4
函数的实用性在于与其它功能结合使用,例如结合map()、()和()。
递归
中的函数可以调用自身,这就是递归。递归在许多情况下都非常有用。
解释递归的常用方法是实现阶乘计算。
一个数字n的阶乘是数字n乘以n-1,再乘以n-2,以此类推,直到数字1:
3! = 3 * 2 * 1 = 6
4! = 4 * 3 * 2 * 1 = 24
5! = 5 * 4 * 3 * 2 * 1 = 120
使用递归,我们可以编写一个计算任意数阶乘的函数:
def factorial(n):
if n == 1: return 1
return n * factorial(n-1)
print(factorial(3)) # 6
print(factorial(4)) # 24
print(factorial(5)) # 120
如果在 () 函数中调用(n)而不是(n-1),则会导致无限递归。默认情况下,将在1000次调用时停止递归,此时您将收到错误。
递归在很多地方都有用,它可以帮助我们在没有其它更好方法的情况下简化代码,所以了解这种技术是件好事。
嵌套函数
中函数可以嵌套在其它函数中。
在函数内部定义的函数仅在该函数内可见。
这对于创建在函数内有用,但在函数外无用的程序很有用。
您可能会问:如果它没有害处,我为什么要“隐藏”这个功能?
因为最好隐藏函数本地并且在其它地方没有用的功能。
另外,这样我们可以使用闭包(稍后会详细介绍)。
这里是一个例子:
def talk(phrase):
def say(word):
print(word)
words = phrase.split(' ')
for word in words:
say(word)
talk('I am going to buy the milk')
如果要从内部函数访问外部函数中定义的变量,首先需要将其声明为:
def count():
count = 0
def increment():
nonlocal count
count = count + 1
print(count)
increment()
count()
这对闭包特别有用,我们将在接下来的说明中看到。
闭包
如果函数返回一个嵌套函数,则该嵌套函数可以访问在该函数中定义的变量,即使该函数不再处于运行状态。
这是一个简单的计数器示例。
def counter():
count = 0
def increment():
nonlocal count
count = count + 1
return count
return increment
increment = counter()
print(increment()) # 1
print(increment()) # 2
print(increment()) # 3
我们返回()这个内部函数,即使()函数已经结束,仍然可以访问count变量的状态。
装饰器
装饰器是一种可以以任何方式增强或改变函数工作方式的方法。
装饰器是用@符号定义的,@后面跟装饰器名称,(装饰器用在)在函数定义之前。
例子:
@logtime
def hello():
print('hello!')
这个hello函数分配了装饰器。
每当我们调用hello()时,装饰器也都会被调用。
装饰器是一个以函数为参数的函数,它将(被装饰的)函数包装在内部函数中,该内部函数执行必须完成的工作,然后返回这个内部函数。换句话说:
def logtime(func):
def wrapper():
# do something before
val = func()
# do something after
return val
return wrapper
文档字符串
文档非常重要,不仅可以用于告知其他人(自己写的)函数/类/方法/模块的目标是什么,还可以帮助您(在较长时间后)理解自己的代码。
当您在6或12个月后会看您的的代码时,可能不记得写代码时脑海中的所有想法。这个时候阅读您的代码并理解它在做什么将变得非常困难。
注释是帮助自己(和他人)摆脱这种困境的一种方式:
# this is a comment
num = 1 # this is another comment
另一种方法是使用。
文档字符串的实用性在于它们遵循约定,因此它们可以被自动处理。
这是您为函数定义文档字符串的方式:
def increment(n):
"""Increment a number"""
return n + 1
这是为类和方法定义文档字符串的方式:
class Dog:
"""A class representing a dog"""
def __init__(self, name, age):
"""Initialize a new dog"""
self.name = name
self.age = age
def bark(self):
"""Let the dog bark"""
print('WOF!')
通过在文件顶部放置一个文档字符串来解释记录一个模块,例如,假设这是dog.py:
"""Dog module
This module does ... bla bla bla and provides the following classes:
- Dog
...
"""
class Dog:
"""A class representing a dog"""
def __init__(self, name, age):
"""Initialize a new dog"""
self.name = name
self.age = age
def bark(self):
"""Let the dog bark"""
print('WOF!')
文档字符串可以跨越多行:
def increment(n):
"""Increment
a number
"""
return n + 1
将处理这些(文档字符串),您可以使用全局函数help()来获取类/方法/函数/模块的文档。
例如调用help()会给返回这个:
Help on function increment in module
__main__:
increment(n)
Increment
a number
格式化文档字符串有许多不同的标准,您可以选择遵守自己喜欢的标准。
我喜欢谷歌的标准:#38–and-
(遵循)标准可以使用工具来提取文档字符串并自动为您的代码生成文档。
反射
可以使用反射来分析函数、变量和对象。
首先,使用全局函数help()(如果以文档字符串的形式提供)我们可以获得文档。
然后,您可以使用print()获取有关函数的信息:
def increment(n):
return n + 1
print(increment)
#
或者(获取)对象(的信息):
class Dog():
def bark(self):
print('WOF!')
roger = Dog()
print(roger)
#
我们可以使用type()函数获取对象的类型:
print(type(increment))
#
print(type(roger))
#
print(type(1))
#
print(type('test'))
#
全局函数dir()可以找出对象的所有方法和属性:
print(dir(roger))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'bark']
全局函数id()显示任意对象在内存中的位置:
print(id(roger)) # 140227518093024
print(id(1)) # 140227521172384
这对于检查两个变量是否指向同一个对象会很有用。
标准库模块为我们提供了更多获取对象信息的工具,您可以在这里查看
注解
是动态类型的,我们不必指定变量、函数参数或函数返回值的类型。
注解允许我们(可选地)这样做。
这是一个没有注解的函数:
def increment(n):
return n + 1
这是带有注解的相同函数:
def increment(n: int) -> int:
return n + 1
您还可以注解变量:
count: int = 0
将忽略这些注解。一个名为mypy的工具可以独立运行,也可以集成到VS Code或等IDE中,以便在您编码时自动检查静态类型错误。它还将帮助您在运行代码之前捕获类型不匹配的错误。
这是一个很大的帮助,尤其是当您的软件规模变得很大并且需要重构代码时。
异常
处理错误很重要,为我们提供了异常处理来做到这一点。
如果将代码行包装到try:块中:
try:
# 一些代码
如果发生错误,会提醒您,您可以使用块确认发生了哪种错误:
try:
# 一些代码
except :
# 处理
except :
# 处理
要捕获所有异常,您可以使用不包含任何错误类型的块:
try:
# 一些代码
except :
# 处理
except:
# 捕获其它所有错误
如果没有发现异常,则将运行else块:
try:
# 一些代码
except :
# 处理
except :
# 处理
else:
# 没有抛出异常,代码成功运行
块允许您在任何情况下执行某些操作,无论是否发生错误:
try:
# 一些代码
except :
# 处理
except :
# 处理
else:
# 没有抛出异常,代码成功运行
finally:
# 任何情况下都将运行的代码
将发生的具体错误取决于您正在执行的操作。
例如,如果您正在读取一个文件,可能会得到一个。如果您将一个数除以零,将会得到一个。如果发生类型转换问题,您可能会得到一个。
试试这个代码:
result = 2 / 0
print(result)
程序将因错误而终止:
Traceback (most recent call last):
File "main.py", line 1, in
result = 2 / 0
ZeroDivisionError: division by zero
并且错误(代码行)之后的代码将不会被执行。
在try:块中添加该操作可以让我们优雅地恢复(错误)并继续执行程序:
try:
result = 2 / 0
except ZeroDivisionError:
print('Cannot divide by zero!')
finally:
result = 1
print(result) # 1
您也可以在自己的代码中使用raise语句引发异常:
raise Exception('An error occurred!')
这会抛出一个异常,您可以使用以下方法拦截它:
try:
raise Exception('An error occurred!')
except Exception as error:
print(error)
您还可以扩展来定义自己的异常类:
class DogNotFoundException(Exception):
pass
这里pass的意思是“什么都没有”,当我们定义一个没有方法的类或没有代码的函数时,我们必须使用它。
try:
raise DogNotFoundException()
except DogNotFoundException:
print('Dog not found!')
中with语句
with语句对于简化异常处理非常有帮助。
例如,在处理文件时,每次打开文件都必须记得关闭它。
with使这个过程变得透明(即对程序员不可见)。
(使用with)可以不像下面这样写:
filename = '/Users/flavio/test.txt'
try:
file = open(filename, 'r')
content = file.read()
print(content)
finally:
file.close()
您可以这样写:
filename = '/Users/flavio/test.txt'
with open(filename, 'r') as file:
content = file.read()
print(content)
换句话说,有内置的隐式异常处理,其会自动为我们调用close()。
上面的例子只是为了介绍with的功能,而不是说它仅在处理文件方面对我们有帮助。
如何使用pip安装第三方包
标准库包含大量实用的程序,可以简化我们的开发需求,但是没有什么能满足_一切_。
这就是个人和公司创建第三方包,并将它们作为开源软件提供给整个社区的原因。
这些模块都收集在一个地方,可在 获得包索引,并且可以使用pip将它们(第三方模块)安装在您的系统上。
在撰写本文时,有超过270,000个免费第三方包可供我们使用。
如果您按照安装说明进行操作,您应该已经安装了 pip。
使用命令pip 可以安装任何第三方包:
pip install
或者,如果您确实遇到了问题,也可以通过 -m运行它:
python -m pip install
例如,您可以安装 包,这是一个流行的 HTTP 库:
pip install requests
一旦这样做,它就可以用于您所有的脚本,因为包是全局安装的。
(第三方包安装的)具体位置取决于您的操作系统。
在运行 3.9的macOS上,位置是///.//3.9/lib/.9/site-。
使用以下命令将第三方包升级到最新版本:
pip install –U
使用以下命令安装指定版本的第三方包:
pip install ==
使用以下命令卸载一个第三方包:
pip uninstall
使用以下命令显示已安装第三方包的详细信息,包括版本、文档网站和作者信息:
pip show
列表推导式
列表推导式以一种非常简洁的方式创建列表。
假设有一个列表:
numbers = [1, 2, 3, 4, 5]
您可以使用列表推导式创建一个新列表,该列表由列表元素的2次幂组成:
numbers_power_2 = [n**2 for n in numbers]
# [1, 4, 9, 16, 25]
列表推导是一种有时比循环更受欢迎的语法,因为当(有些)操作写在一行时其更具可读性:
numbers_power_2 = []
for n in numbers:
numbers_power_2.append(n**2)
同样有时也比map()更好:
numbers_power_2 = list(map(lambda n : n**2, numbers))
多态
多态将一个功能泛化,因此它可以在不同的类型上工作。多态是面向对象编程中的一个重要概念。
我们可以在不同的类上定义相同的方法:
class Dog:
def eat():
print('Eating dog food')
class Cat:
def eat():
print('Eating cat food')
然后我们可以生成对象,无论对象属于哪个类,我们都可以调用eat()方法,但是会得到不同的结果:
animal1 = Dog()
animal2 = Cat()
animal1.eat()
animal2.eat()
我们构建了一个通用接口,不需要知道动物是猫还是狗。
译者:这个例子不太好,不完整,看下面这个例子:
In [1]: class Animal:
...: def eat(self):
...: print("animal eating ...")
...:
In [2]: class Dog(Animal):
...: def eat(self):
...: print("dog eating ...")
...:
In [3]: class Cat(Animal):
...: def eat(self):
...: print("cat eating ...")
...:
In [4]: a = Animal()
In [5]: d = Dog()
In [6]: c = Cat()
In [7]: a.eat()
animal eating ...
In [8]: d.eat()
dog eating ...
In [9]: c.eat()
cat eating ...
译者:多态实际上是看运行时对象具体的类型,在Java中,是可以这样写的 dog = new Dog(),即创建一个对象dog,这是编译时,但是在运行时dog.eat()打印dog …
运算符重载
运算符重载是一种先进的技术,我们可以用来使类具有可比性,并使它们与运算符一起工作。
让我们来创建一个类Dog:
class Dog:
# the Dog class
def __init__(self, name, age):
self.name = name
self.age = age
创建两个Dog对象:
roger = Dog('Roger', 8)
syd = Dog('Syd', 7)
我们可以使用运算符重载添加一种基于age属性的方法来比较这两个对象:
class Dog:
# the Dog class
def __init__(self, name, age):
self.name = name
self.age = age
def __gt__(self, other):
return True if self.age > other.age else False
现在如果您尝试运行print(roger > syd),将得到结果True。
与我们定义()(大于)的方式相同,我们可以定义以下方法:
然后还有使用算术运算符操作的方法:
还有其它几种方法可以与运算符一起使用,但您应该明白了(这种思想)。
虚拟环境
在您的系统上运行多个应用程序是很常见的。
当应用程序需要相同的模块时,有时您会遇到一个棘手的情况,即一个应用程序需要一个版本模块,而另一个应用程序需要该模块的不同版本。
您可以使用虚拟环境解决这个问题。
我们将使用venv。其它工具的工作方式类似,例如。
如下创建虚拟环境
python -m venv .venv
(该命令)在您要开始的项目的文件夹或者现有项目的文件夹(的根目录下运行)。
译者:项目的根目录即其本身,例如一个项目fCC在/Users/abc//fCC,那么该项目的根目录就是/Users/abc//fCC/
然后运行
source .venv/bin/activate
(如果是)在Fish shell上,使用 .venv/bin/.fish
执行这个命令将激活虚拟环境。根据您的配置,可能还会看到终端提示发生变化。
我的从
变成
(.venv)
现在运行pip将使用这个虚拟环境而不是全局环境。
总结
非常感谢您阅读本书。
我希望它能鼓励您更多去地了解 。
有关和一般编程教程的更多信息,请查看我的博客 .com。
你可以发送邮件至 @.com提供任何反馈、勘误或意见。
请注意:您可以获取此手册的PDF、ePub和Mobi版本
原文链接:
加入IP合伙人(站长加盟) | 全面包装你的品牌,搭建一个全自动交付的网赚资源独立站 | 晴天实测8个月运营已稳定月入3W+
限时特惠:本站每日持续更新海量内部创业教程,一年会员只需98元,全站资源免费无限制下载点击查看会员权益
站长微信: qtw123cn
