Python 中的变量:用法和最佳实践
Python 中的变量:用法和最佳实践
在 Python 中,变量是指向存储在计算机内存中的对象或值的符号名称。它们允许您为数据分配描述性名称,从而更轻松地在整个代码中操作和重用值。
了解变量对于 Python 开发人员来说至关重要,因为变量是任何 Python 程序的基本构建块。正确使用变量可让您编写清晰、可读且可维护的代码。
在本教程中,您将学习如何:
创建变量并为其赋值
动态更改变量的数据类型
使用变量创建表达式、计数器、累加器和布尔标志
遵循变量命名的最佳实践
在作用域内创建、访问和使用变量
为了充分利用本教程,您应该熟悉 Python 的基本数据类型并对循环和函数等编程概念有一般的了解。
了解 Python 中的变量
在 Python 中,变量是与存储在计算机内存中的具体对象或值相关联的名称。通过将变量与值关联,您可以使用描述性名称引用该值,并根据需要在代码中多次重复使用它。
变量的行为就像它们引用的值一样。要在代码中使用变量,您首先需要了解如何创建变量,这在 Python 中非常简单。
创建带有赋值的变量
在 Python 中创建变量的主要方法是使用赋值运算符和以下语法为其赋值:
Python 语法
variable_name = value
在此语法中,左侧是变量的名称,然后是赋值 ( =
) 运算符,后面是要分配给当前变量的值。此结构中的值可以是任何 Python 对象,包括字符串、数字、列表、字典,甚至是自定义对象。
以下是一些变量的示例:
Python
>>> word = "Python"
>>> number = 42
>>> coefficient = 2.87
>>> fruits = ["apple", "mango", "grape"]
>>> ordinals = {1: "first", 2: "second", 3: "third"}
>>> class SomeCustomClass: pass
>>> instance = SomeCustomClass()
在此代码中,您通过为名称赋值定义了几个变量。前五个示例包括引用不同内置类型的变量。最后一个示例表明变量还可以引用自定义对象,例如类的实例SomeCustomClass
。
设置和更改变量的数据类型
除了变量的值之外,考虑值的数据类型也很重要。考虑变量的类型时,您要考虑变量是指字符串、整数、浮点数、列表、元组、字典、自定义对象还是其他数据类型。
Python 是一种动态类型语言,这意味着变量类型是在运行时而不是在编译期间确定和检查的。因此,您在创建变量时无需指定变量的类型。Python 将从分配的对象中推断变量的类型。
注意:在 Python 中,变量本身没有数据类型。相反,变量引用的对象才具有类型。
例如,考虑以下变量:
Python
>>> name = "Jane Doe"
>>> age = 19
>>> subjects = ["Math", "English", "Physics", "Chemistry"]
>>> type(name)
<class 'str'>
>>> type(age)
<class 'int'>
>>> type(subjects)
<class 'list'>
在这个例子中,name
指的是"Jane Doe"
值,所以 的类型name
是str
。同样,age
指的是整数19
,所以它的类型是int
。最后,subjects
指的是列表,所以它的类型是list
。请注意,您不必明确告诉 Python 每个变量的类型。Python 通过检查分配值的类型来确定和设置类型。
因为 Python 是动态类型的,所以你可以通过重新分配变量来使变量在不同时刻引用不同数据类型的对象:
Python
>>> age = "19"
>>> type(age)
<class 'str'>
>>> subjects = {"Math", "English", "Physics", "Chemistry"}
>>> type(subjects)
<class 'set'>
现在,age
引用字符串,并subjects
引用集合对象。通过为现有变量分配不同类型的值,可以更改变量的类型。
在 Python 中使用变量
变量是 Python 编程中的一个重要概念。它们是程序的构建块。到目前为止,您已经学习了创建变量的基础知识。在本节中,您将探索在 Python 中使用变量的不同方法。
您将从在表达式中使用变量开始。然后,您将深入了解计数器和累加器,它们对于在迭代期间跟踪值至关重要。您还将了解变量的其他常见用例,例如临时变量、布尔标志、循环
变量和数据存储变量。
表达式
在 Python 中,表达式是一个简单的语句,Python 可以对其进行求值以生成并返回一个值。例如,考虑以下计算两个不同圆的周长的表达式:
Python
>>> 2 * 3.1416 * 10
62.912
>>> 2 * 3.1416 * 20
125.824
每个表达式都代表一个特定的计算。为了构建表达式,您使用了值和乘法运算符 ( *
)。Python 会评估每个表达式并返回结果值。
上述表达式有些死板。对于每个表达式,您必须重复输入值,这是一项容易出错且重复的任务。
现在考虑以下例子:
Python
>>> pi = 3.1416
>>> radius = 10
>>> 2 * pi * radius
62.912
>>> radius = 20
>>> 2 * pi * radius
125.824
在此示例中,您首先定义变量来保存输入值。然后,在表达式中使用这些变量。请注意,当您使用变量构建表达式时,Python 会用变量的值替换变量。如示例所示,您可以方便地在不同的表达式中重复使用这些值。
要注意的另一个重要点是,现在您有了描述性名称来正确识别表达式中使用的值。
总而言之,变量非常适合在表达式中重复使用值,并使用随时间变化的数据运行计算。一般来说,变量可以让您命名或标记对象,以便稍后在程序中引用和操作它们。在以下部分中,您将看到变量在实践中的用例。
计数器
计数器是一个整数变量,可用于对对象进行计数。计数器的初始值通常为零,该值会递增以反映给定对象出现的次数。为了说明这一点,假设您需要对给定对象列表中的字符串对象进行计数。在这种情况下,您可以执行以下操作:
Python
>>> str_counter = 0
>>> for item in ("Alice", 30, "Programmer", None, True, "Department C"):
... if isinstance(item, str):
... str_counter += 1 ...
>>> str_counter
3
在此示例中,您str_counter通过将变量初始化为 来创建变量0。然后,对不同类型的对象列表运行循环for。在循环内部,使用内置isinstance()函数检查当前对象是否为字符串。如果当前对象是字符串,则将计数器加一。
在循环结束时,str_counter
其值为3
,反映了输入列表中字符串对象的数量。
注意:上例中突出显示的行使用表达式str_counter += 1,它是 的快捷方式str_counter = str_counter + 1。该+=运算符称为增强加法运算符。
str_counter += 1
您可以在循环的每次迭代中重复使用表达式来增加 的值,使其随时间变化。这种动态更新是变量的一个关键特性。正如变量的str_counter
名称所暗示的那样,它们旨在保存随时间变化的值。
累加器
累加器是编程中另一种常见的变量类型。累加器是一种变量,可用于将连续的值相加以形成总数,并可将其用作不同计算的中间步骤。
累加器的一个典型示例是当您需要计算数值的总和时:
Python
>>> numbers = [1, 2, 3, 4]
>>> total = 0
>>> for number in numbers:
... total += number ...
>>> total
10
在此示例中,循环遍历数字列表并累加 中的每个值total
。您还可以使用累加器作为更大规模计算的一部分,例如计算数字列表的平均值:
Python
>>> total / len(numbers)
2.5
然后,您可以total利用内置len()函数计算平均值。您可以使用对象计数器代替len()。同样,Python 附带了几个累加器函数,您可以经常使用这些函数来代替显式累加器。例如,您可以使用sum()而不是total像上面那样计算。
临时变量
临时变量保存更复杂计算所需的中间结果。临时变量的一个典型用例是当你需要在变量之间交换值时:
Python
>>> a = 5
>>> b = 10
>>> temp = a
>>> a = b
>>> b = temp
>>> a
10
>>> b
5
在此示例中,您使用名为 的临时变量temp
来保存 的值a
,以便可以在a
和 之间交换值b
。一旦完成交换,temp
就不再需要 了。
注意:在 Python 中,有一种简洁优雅的方法可以在不使用临时变量的情况下在变量之间交换值。您将在可迭代对象解包部分中了解此主题。
有关使用临时变量的更详细示例,请考虑以下计算数值数据样本方差的函数:
Python
>>> def variance(data, degrees_of_freedom=0):
... return sum((x - sum(data) / len(data)) ** 2 for x in data) / ( ... len(data) - degrees_of_freedom ... ) ...
>>> variance([3, 4, 7, 5, 6, 2, 9, 4, 1, 3])
5.24
用作函数返回值的表达式相当复杂,难以理解。由于您在单个表达式中运行多个操作,因此调试起来也很困难。
为了使您的代码更易于理解和调试,您可以利用增量开发方法,该方法使用临时变量进行中间计算:
Python
>>> def variance(data, degrees_of_freedom=0):
... number_of_items = len(data)
... mean = sum(data) / number_of_items
... total_square_dev = sum((x - mean) ** 2 for x in data)
... return total_square_dev / (number_of_items - degrees_of_freedom) ...
>>> variance([3, 4, 7, 5, 6, 2, 9, 4, 1, 3])
5.24
在此替代实现中variance()
,您可以分几步计算方差。每一步都由一个具有有意义名称的临时变量表示,从而使您的代码更具可读性。
布尔标志
布尔标志可帮助您管理程序中的控制流和决策。顾名思义,这些变量可以是True或。您可以在条件、循环和布尔表达式False中使用它们。while
假设您需要在循环中交替执行两个不同的操作。在这种情况下,您可以使用标志变量在每次迭代中切换操作:
Python
>>> toggle = True
>>> for _ in range(4):
... if toggle:
... print(f"✅ toggle is {toggle}")
... print("Do something...")
... else:
... print(f"❌ toggle is {toggle}")
... print("Do something else...")
... toggle = not toggle ...
✅ toggle is True
Do something...
❌ toggle is False
Do something else...
✅ toggle is True
Do something...
❌ toggle is False
Do something else...
每次运行此循环时,条件都会检查 的值toggle以决定采取哪种操作。在循环结束时,您可以toggle使用not运算符更改 的值。下一次迭代将运行替代操作
标志也可用作函数参数。请考虑以下示例:
Python
>>> def greet(name, verbose=False):
... if verbose:
... print(f"Hello, {name}! It's great to see you!")
... else:
... print(f"Hello, {name}!")
...
>>> greet("Pythonista")
Hello, Pythonista!
>>> greet("Pythonista", verbose=True)
Hello, Pythonista! It's great to see you!
在此示例中,verbose
参数是一个布尔变量,可让您决定显示哪条问候消息。
您会发现一些 Python 内置函数使用标志参数。该sorted()函数就是一个很好的例子:
Python
>>> sorted([4, 2, 7, 5, 1, 6, 3])
[1, 2, 3, 4, 5, 6, 7]
>>> sorted([4, 2, 7, 5, 1, 6, 3], reverse=True)
[7, 6, 5, 4, 3, 2, 1]
该sorted()
函数以可迭代对象为参数,并返回已排序对象的列表。此函数有一个reverse
参数,它是一个标志,默认为False
。如果将此参数设置为True
,则会以相反的顺序对对象进行排序。
is_
在实践中,您会发现布尔变量通常使用或命名模式命名has_
:
Python
>>> age = 20
>>> is_adult = age > 18
>>> is_adult
True
在此示例中,is_adult
变量是一个根据 的值而变化的标志age
。请注意,is_
命名模式可让您清楚地传达变量的用途。但是,这种命名约定只是一种常见的做法,而不是要求或 Python 强化的东西。
循环变量
for
循环变量可帮助您在循环中(有时在循环中)处理迭代过程中的数据while
。在for
循环中,每次循环时,变量都会获取输入可迭代对象中当前元素的值:
Python
>>> colors = [
... "red",
... "orange",
... "yellow",
... "green",
... "blue",
... "indigo",
... "violet"
... ]
>>> for color in colors:
... print(color)
...
red
orange
yellow
green
blue
indigo
violet
在此示例中,您使用循环迭代颜色列表for
。循环变量color
保存每次迭代中的当前颜色。这样,您可以在迭代数据时对当前项执行某些操作。
Python 的for
循环可以有多个循环变量。例如,假设您想将每种颜色与其索引进行映射。在这种情况下,您可以执行以下操作:
Python
>>> for index, color in enumerate(colors):
... print(index, color)
...
0 red
1 orange
2 yellow
3 green
4 blue
5 indigo
6 violet
在此示例中,您使用内置enumerate()函数在迭代输入数据时生成索引。请注意此循环有两个变量。要提供多个循环变量,请使用逗号分隔的一系列变量。
您还可以使用变量来控制while
循环。这是一个示例:
Python
>>> count = 5
>>> while count:
... print(count)
... count -= 1
...
5
4
3
2
1
在此示例中,循环变量充当定义迭代次数的计数器。在循环内部,使用增强减法运算符 ( -=
) 来更新变量的值。
数据存储变量
数据存储变量允许您使用值的容器,例如列表、元组、字典或集合。例如,假设您正在编写一个通讯录应用程序,该应用程序使用元组列表来存储联系人的信息:
Python
>>> contacts = [
... ("Linda", "111-2222-3333", "linda@example.com"),
... ("Joe", "111-2222-3333", "joe@example.com"),
... ("Lara", "111-2222-3333", "lara@example.com"),
... ("David", "111-2222-3333", "david@example.com"),
... ("Jane", "111-2222-3333", "jane@example.com"),
... ]
此contacts
变量允许您使用单个描述性名称来操作数据。您可以在循环中使用变量,例如:
Python
>>> for contact in contacts:
... print(contact)
...
('Linda', '111-2222-3333', 'linda@example.com')
('Joe', '111-2222-3333', 'joe@example.com')
('Lara', '111-2222-3333', 'lara@example.com')
('David', '111-2222-3333', 'david@example.com')
('Jane', '111-2222-3333', 'jane@example.com')
>>> for name, phone, email in contacts:
... print(phone, name)
...
111-2222-3333 Linda
111-2222-3333 Joe
111-2222-3333 Lara
111-2222-3333 David
111-2222-3333 Jane
第一个循环迭代联系人列表中的项目并将它们打印为元组。第二个循环使用三个循环变量分别处理每条数据。
请注意,在循环中,您可以根据需要使用变量。您不需要使用所有变量或以相同的顺序使用它们。但是,当您有一个未使用的变量时,您应该使用下划线命名它,以指出它是一个一次性变量。
因此,你可以将循环头重写为如下所示:for name, phone, _ in contacts:
。在本例中,下划线代表电子邮件变量,你不会在循环主体中使用该变量。
在 Python 中命名变量
到目前为止您看到的示例都使用了简短的变量名。实际上,变量名应该具有描述性,以提高代码的可读性,因此变量名也可以更长,并包含多个单词。
在以下部分中,您将了解在 Python 中创建有效变量名时应遵循的规则。您还将了解命名变量的最佳实践以及其他与命名相关的实践。
变量命名规则
Python 中的变量名可以是任意长度,可以由大写字母 ( A-Z
) 和小写字母 ( a-z
)、数字 ( 0-9
) 和下划线 ( _
) 组成。唯一的限制是,即使变量名可以包含数字,变量名的第一个字符也不能是数字。
注意: Python 目前完全支持Unicode,您可以在变量名中使用许多 Unicode 字符。例如,以下变量名是有效的:
Python
>>> α = 45 >>> β = 90 >>> δ = 180 >>> π = 3.14
这些变量名在 Python 代码中可能并不常见,但它们完全有效。当您希望代码反映目标学科中使用的符号时,您可以在执行科学计算的代码中使用它们。
以下都是有效的变量名:
Python
>>> name = "Bob"
>>> year_of_birth = 1970
>>> is_adult = True
这些变量遵循在 Python 中创建有效变量名的规则。它们还遵循最佳命名实践,您将在下一节中了解这些实践。
下面的变量名不符合规则:
Python
>>> 1099_filed = False
File "<input>", line 1
1099_filed = False
^
SyntaxError: invalid decimal literal
此示例中的变量名以数字开头,这在 Python 中是不允许的。因此,您会收到SyntaxError异常
重要的是要知道变量区分大小写。小写字母和大写字母的处理方式不同:
Python
>>> age = 1
>>> Age = 2
>>> aGe = 3
>>> AGE = 4
>>> age
1
>>> Age
2
>>> aGe
3
>>> AGE
4
在此示例中,Python 将名称解释为不同的独立变量。因此,在 Python 中创建变量名时需要考虑大小写。
没有什么可以阻止您在同一个程序中创建两个不同的变量,分别称为age
和Age
,或者agE
。但是,不建议这样做,因为它会让试图阅读您的代码的人感到困惑,甚至一段时间后您自己也会感到困惑。通常,创建变量名时应使用小写字母。
下划线字符的使用也很重要。您将使用下划线分隔变量名中的多个单词:
Python
>>> first_name = "John"
>>> pen_color = "red"
>>> next_node = 123
在这些变量名中,您使用下划线字符作为多个单词的分隔符。这是一种通过将空格字符替换为下划线来提高代码可读性的方法。为了说明这一点,请考虑没有下划线的变量的外观:
Python
>>> firstname = "John"
>>> pencolor = "red"
>>> nextnode = 123
尽管这些名称在技术上是有效的,但乍一看却很难阅读和理解。缺乏区分使得很难快速掌握每个变量的含义,并且需要付出更多努力才能解释清楚。使用下划线可以提高代码的清晰度,使其更易于维护。
命名变量的最佳实践
您应该始终为变量指定一个描述性名称,以清楚地说明变量的用途。有时,您可以找到一个单词来命名给定的变量:
Python
>>> temperature = 25
>>> weight = 54.5
>>> message = "Hello, Pythonista!"
变量总是引用具体对象,因此它们的名称应该是名词。您应该尝试为变量找到能够唯一标识所引用对象的特定名称。诸如 、 或 之类的名称variable
可能data
过于value
通用。虽然这些名称可以用于简短的示例,但它们对于生产代码来说不够具有描述性。
一般来说,你应该避免使用单字母名称:
Python
>>> t = 25 # Don't do this
>>> temperature = 25 # Do this instead
单字母名称可能难以辨认,从而使您的代码难以阅读,尤其是当您在具有其他类似名称的表达式中使用它们时。当然,也有例外。例如,如果您使用嵌套列表,则可以使用单字母名称来标识索引:
Python
>>> matrix = [
... [9, 3, 8],
... [4, 5, 2],
... [6, 4, 3],
... ]
>>> for i in matrix:
... for j in i:
... print(j)
...
9
3
8
4
5
2
6
4
3
通常使用i
、j
和等字母k
来表示索引,因此您可以在正确的上下文中使用它们。通常使用x
、y
和z
来表示点坐标,因此也可以使用这些字母。
不鼓励使用缩写来命名变量,而建议使用完整的名称:
Python
>>> doc = "Freud" # Don't do this
>>> doctor = "Freud" # Do this instead
最佳做法是使用完整名称而不是缩写名称,因为缩写更易读、更清晰。不过,有时缩写被广泛接受和使用时也是可以的:
Python
>>> cmd = "python -m pip list"
>>> msg = "Hello, Pythonista!"
在这些例子中,是命令cmd
的常用缩写,是消息的常用缩写。Python 中广泛使用的缩写的一个经典示例是名称,您应该使用它来在类方法中标识当前类对象。msg
cls
有时,你需要多个单词来构建一个描述性变量名。使用多词名称时,如果单词之间没有可区分的界限,你可能会很难阅读它们:
Python
>>> numberofgraduates = 200
这个变量名读起来比较困难。你必须仔细弄清楚单词的边界,这样才能理解这个变量代表什么。
多字变量名最常见的做法如下:
number_of_graduates
。numberOfGraduates
。NumberOfGraduates
。Python 代码样式指南(也称为PEP 8)包含命名约定,其中列出了不同对象类型名称的建议标准。关于变量,PEP 8 建议使用蛇形命名风格。
当你需要多词名称时,通常将形容词作为限定词与名词结合起来:
Python
>>> initial_temperature = 25
>>> current_file = "marketing_personel.csv"
>>> next_point = (2, 4)
在这些示例中,您可以通过组合形容词和名词来创建描述性变量名,这可以显著提高代码的可读性。另一个需要考虑的点是避免使用以 开头的多词名称my_
,例如my_file
、my_color
等等。这my_
部分实际上不会为名称添加任何有用的东西。
标志变量是何时使用多字变量名的另一个很好的例子:
Python
>>> is_authenticated = True
>>> has_permission = False
在这些例子中,您使用下划线来分隔单词,使得它们的边界可见且易于发现。
当命名列表和词典时,大多数情况下应该使用复数名词:
Python
>>> fruits = ["apple", "banana", "cherry"]
>>> colors = {
... "Red": (255, 0, 0),
... "Green": (0, 255, 0),
... "Blue": (0, 0, 255),
... "Yellow": (255, 255, 0),
... "Black": (0, 0, 0),
... "White": (255, 255, 255),
... }
在这些例子中使用复数名词可以清楚地表明变量指的是存储几个相似类型的对象的容器。
在命名元组时,您应该考虑到它们通常用于存储不同类型或含义的对象。因此,使用单数名词是可以的:
Python
>>> color = (255, 0, 0)
>>> row = ("Jane", 25, "Python Dev", "Canada")
虽然这些元组存储了多个对象,但它们代表单个实体。第一个元组表示RGB(红、绿、蓝)颜色,而第二个元组表示数据库表中的一行或其他表格数据。
公共和非公共变量名称
Python 中广泛使用的变量命名约定是,当您需要传达给定变量是 Python 定义为non-public 的变量时,使用前导下划线。非公共变量是不应在其定义模块之外使用的变量。这些变量仅供内部使用:
Python
_timeout = 30
def get_timeout():
return _timeout
def set_timeout(seconds):
global _timeout
_timeout = seconds
在此模块中,您有一个名为 的非公共变量_timeout
。然后,您有几个使用此变量的函数。但是,变量本身不打算在包含模块之外使用。
受限制和不鼓励使用的名称
Python 保留了一小组称为关键字的单词,它们是该语言语法的一部分。要获取 Python 关键字列表,请继续运行以下代码:
Python
>>> import keyword
>>> keyword.kwlist
[
'False',
'None',
'True',
'and',
'as',
'assert',
'async',
...,
'yield'
]
在大多数情况下,您将无法使用这些词作为变量名,否则会出现错误:
Python
>>> class = "Business"
File "<input>", line 1
class = "Business"
^
SyntaxError: invalid syntax
这种行为对于大多数关键字都是正确的。如果您需要使用与关键字一致的名称,那么您可以遵循 PEP 8 的建议,即在名称后面添加一个下划线:
Python
>>> class_ = "Business"
在此示例中,您在关键字末尾添加了一个下划线字符,这样您就可以将其用作变量名。尽管这种约定有效,但有时执行如下操作更为优雅:
Python
>>> passenger_class = "Business"
现在,您的变量名称更具描述性和具体性,从而提高了代码的可读性。
还有软关键词,即只在特定语境中才为关键词。例如,关键词只在结构模式匹配match中才被视为关键词。
由于match
是一个软关键字,因此您可以使用它来命名变量:
Python
>>> import re
>>> text = "Some text containing a number: 123"
>>> match = re.search("123", text)
>>> if match: ... print("Found a match 😃")
... else:
... print("No match found 😔")
...
Found a match 😃
在此示例中,您导入re
模块以使用正则表达式。此示例仅在目标文本中搜索基本表达式。这里的想法是表明match即使它是一个关键字,也可以用作有效的变量名。
您应该避免的另一种做法是使用内置名称来命名变量。为了说明这一点,假设您正在学习 Python 列表并运行以下代码:
Python
>>> list = [1, 2, 3, 4]
>>> list
[1, 2, 3, 4]
在此示例中,您已将其用作包含数值的对象list
的名称list
。这会将原始对象隐藏在名称后面,从而阻止您在代码中使用它:
Python
>>> list(range(10))
Traceback (most recent call last):
...
TypeError: 'list' object is not callable
现在,调用list()
失败,因为您已在代码中覆盖了内置名称。因此,最好避免使用内置名称来定义变量。这种做法可能会以不同的方式导致代码失败。
注意:要获取内置名称的完整列表,请在交互式会话中运行以下代码:
Python
>>> import builtins >>> dir(builtins) [ 'ArithmeticError', 'AssertionError', 'AttributeError', ... 'tuple', 'type', 'vars', 'zip' ]
内置名称列表很长。要确保您的变量名称不会覆盖此列表中的某个名称,您可以执行类似 的操作"name" in dir(builtins)。如果此检查返回True,则最好查找其他名称。
请注意,此建议也适用于引用您在代码中使用的第三方库中定义的对象的名称。
探索变量的核心特征
当您开始深入研究 Python 变量的内部工作原理时,您会发现一些值得研究的有趣功能。在以下部分中,您将探索变量的一些核心功能,以便更好地理解它们。
变量保存对对象的引用
当您通过赋值创建变量时会发生什么?这是 Python 中的一个重要问题,因为答案与许多其他编程语言中的答案不同。
Python 是一种面向对象的编程语言。Python 程序中的每部分数据都是特定类型或类的对象。请考虑以下代码:
Python
>>> 300
300
当出现该语句时300
,Python 会执行以下操作:
- 创建一个整数对象
- 赋予其值为
300
- 将其显示在屏幕上
可以看到使用内置type()函数创建了一个整数对象:
Python
>>> type(300)
<class 'int'>
Python 变量是指向或引用
某个对象的符号名称,例如300
。将对象分配给变量后,您可以通过变量的名称引用它,但数据本身仍包含在对象中。
例如,考虑以下变量定义:
Python
>>> n = 300
此赋值创建一个值为的整数对象300
,并使变量n
指向该对象。下图显示了这种情况是如何发生的:
变量赋值
在 Python 中,变量不存储对象。它们指向或引用对象。每次在 Python 中创建一个对象时,都会为其分配一个唯一的编号,然后将其与变量关联。
内置id()函数返回对象的标识符或身份:
Python
>>> n = 300
>>> id(n)
4399012816
在Python 的标准发行版CPython中,对象的身份与其内存地址一致。因此,CPython 变量存储的是内存地址。通过这些内存地址,变量可以访问存储在内存中的具体对象。
您可以创建指向同一对象的多个变量。换句话说,保存相同内存地址的变量:
Python
>>> m = n
>>> id(n) == id(m)
True
在此示例中,Python 不会创建新对象。它创建一个新的变量名或引用,m
它指向n
指向以下内容的同一对象:
对单个对象的多个引用
接下来假设你做这样的事情:
Python
>>> m = 400
现在,Python 创建了一个值为 的新整数对象400
,并m
成为对它的引用:
对单独对象的引用
最后,假设您运行以下语句:
Python
>>> n = "foo"
现在,Python 创建一个具有该值的字符串对象"foo"
并引用n
该对象:
孤立对象
由于n
和m
重新分配,您不再拥有对整数对象的引用300
。它是孤立的,您无法再次访问它。
当对某个对象的引用降至零时,该对象将不再可访问。此时,它的生命周期就结束了。Python 会回收分配的内存,以便将其用于其他用途。在编程术语中,此过程称为垃圾收集。
变量具有动态类型
在许多编程语言中,变量都是静态类型的,这意味着它们在生命周期内最初被声明为具有特定的数据类型。在该变量的生命周期内分配给该变量的任何值都必须是指定的数据类型。
Python 变量不是这样输入的。在 Python 中,你可以在不同时刻为变量分配不同数据类型的值:
Python
>>> value = "A string value"
>>> value
'A string value'
>>> # Later
>>> value = 23.5
>>> value
23.5
在此示例中,您让value
变量引用或指向另一种类型的对象。由于这一特性,Python 是一种动态类型语言。
需要注意的是,变量数据类型的变化可能会导致运行时错误。例如,如果变量的数据类型意外更改,您可能会遇到与类型相关的错误,甚至会遇到异常:
Python
>>> value = "A string value"
>>> value.upper()
'A STRING VALUE'
>>> # Later
>>> value = 23.5
>>> # Try to use .upper() again
>>> value.upper()
Traceback (most recent call last):
...
AttributeError: 'float' object has no attribute 'upper'
在此示例中,变量类型在代码执行过程中发生变化。当value
指向字符串时,您可以使用.upper()
方法来将字母转换为大写。但是,当类型更改为 时float
,该.upper()
方法不可用,并且您会收到AttributeError
异常。
变量可以使用类型提示
您可以使用类型提示为变量添加显式类型信息。为此,您可以使用以下 Python 语法:
Python 语法
variable: data_type [= value]
方括号不是语法的一部分。它们表示括号内的部分是可选的。是的,您可以声明 Python 变量而不为其赋值:
Python
>>> number: int
>>> number
Traceback (most recent call last):
...
NameError: name 'number' is not defined
第一行的变量声明有效,并且是有效的 Python 语法。但是,此声明实际上并没有为您创建一个新变量。这就是为什么当您尝试访问该number
变量时会引发NameError异常。即使number未定义,Python 也已记录类型提示:
Python
>>> __annotations__
{'number': <class 'int'>}
当涉及到数字和字符串等基本数据类型时,类型提示可能看起来是多余的:
Python
>>> language: str = "Python"
>>> number: int = 42
>>> coefficient: float = 2.87
如果您熟悉 Python 的内置类型,则无需向这些变量添加类型提示,因为您很快就会知道它们分别具有字符串、整数和浮点值。因此,在这种情况下,您可以跳过类型提示。此外,您的静态类型检查器或linter不会发出抱怨。
当您使用集合类型(例如列表、元组、字典和集合)时,情况会有所不同。对于这些类型,为其所含数据提供类型提示是有意义的。
为了说明起见,假设您有以下颜色词典:
Python
>>> colors = {
... "red": "#FF0000",
... "green": "#00FF00",
... "blue": "#0000FF",
... "yellow": "#FFFF00",
... "black": "#000000",
... "white": "#FFFFFF",
... }
在这种情况下,最好有关于键和值的数据类型的信息。您可以使用以下类型提示提供该信息:
Python
>>> colors: dict[str, str] = { ... "red": "#FF0000",
... "green": "#00FF00",
... "blue": "#0000FF",
... "yellow": "#FFFF00",
... "black": "#000000",
... "white": "#FFFFFF",
... }
在此更新的代码中,您明确地表明您的colors
字典将把它的键和值存储为字符串。
为什么这种类型提示很重要?假设在代码的另一部分,你color
定义了另一个字典,如下所示:
Python
>>> colors = {
... "Red": (255, 0, 0),
... "Green": (0, 255, 0),
... "Blue": (0, 0, 255),
... "Yellow": (255, 255, 0),
... "Black": (0, 0, 0),
... "White": (255, 255, 255),
... }
有时候,你可能要同时使用两个字典,但无法明确地知道需要哪个字典。要解决这个问题,你也可以向第二个字典添加类型提示:
Python
>>> colors: dict[str, tuple[int, int, int]] = { ... "Red": (255, 0, 0),
... "Green": (0, 255, 0),
... "Blue": (0, 0, 255),
... "Yellow": (255, 255, 0),
... "Black": (0, 0, 0),
... "White": (255, 255, 255),
... }
此示例中的类型提示更加复杂,但它清楚地表明你的字典将具有字符串键和三个整数的元组作为值。
值得注意的是,当你使用空容器初始化变量时,引用容器数据类型的类型提示变量特别有用:
Python
>>> fruits: list[str] = []
>>> rows: list[tuple[str, int, str]] = []
在这些示例中,您有两个空列表。由于它们具有类型提示信息,因此您可以快速确定内容的数据类型。现在您知道第一个列表将包含字符串,而第二个列表将包含元组,每个元组由三个项目组成:一个字符串、一个整数和另一个字符串值。
请注意,在此示例中,如果您不提供任何类型信息,则静态类型检查器或 linter 将明确抱怨列表的类型提示。
稍后在代码中,您可以使用正确的数据类型将项目附加到每个列表:
Python
>>> fruits.append("apple")
>>> fruits.append("orange")
>>> rows.append(("Jane", 25, "Python Dev"))
>>> rows.append(("John", 30, "Web Dev"))
首先,使用.append()方法将新水果作为字符串添加到 的末尾fruits
,然后将新行添加到 的末尾rows
。
使用互补方式创建变量
在 Python 中,您会发现几种创建新变量的替代方法。有时,同时定义具有相同初始值的多个变量很方便或有必要。为此,您可以使用并行赋值。
在其他情况下,您可能需要使用序列数据类型(如列表或元组)的值初始化多个变量。在这种情况下,您可以使用一种称为可迭代拆包的技术。
您还会遇到需要保留给定表达式的结果值的情况。在这种情况下,您可以使用赋值表达式。
在以下部分中,您将了解创建 Python 变量的所有这些替代或补充方法。
平行分配
Python 还允许你在一行代码中运行多个赋值。此功能可以同时将相同的值分配给多个变量:
Python
>>> is_authenticated = is_active = is_admin = False
>>> is_authenticated
False
>>> is_active
False
>>> is_admin
False
此示例中的并行赋值同时初始化了三个不同但相关的变量False
。这种创建和初始化变量的方式比以下方式更简洁且重复性更低:
Python
>>> is_authenticated = False
>>> is_active = False
>>> is_admin = False
>>> is_authenticated
False
>>> is_active
False
>>> is_admin
False
通过使用并行分配而不是专用分配,您可以使代码更简洁、更少重复。
可迭代对象拆包
可迭代项拆包是一项很酷的 Python 功能,也称为元组拆包。它包括将可迭代项中的值分配到一系列变量中。在大多数情况下,变量的数量将与可迭代项中的项目数量相匹配。但是,您也可以使用该*variable
语法来抓取列表中的多个项目。
您可以使用可迭代对象解包来使用可迭代值一次创建多个变量。例如,假设您有一些关于某人的数据,并且想要为每条数据创建专用变量:
Python
>>> person = ("Jane", 25, "Python Dev")
如果您不了解可迭代解包,那么您的第一种方法可能是手动将数据分配到不同的变量中,如下所示:
Python
>>> name = person[0]
>>> age = person[1]
>>> job = person[2]
>>> name
'Jane'
>>> age
25
>>> job
'Python Dev'
此代码有效。但是,使用索引提取数据可能会导致容易出错且难以阅读的结果。您可以利用可迭代解包来代替使用此技术,最终得到以下代码:
Python
>>> name, age, job = person
>>> name
'Jane'
>>> age
25
>>> job
'Python Dev'
现在,您的代码看起来更简洁、更易读。因此,当您发现自己使用索引从可迭代对象创建变量时,请考虑使用解包。
解包的一个很好的用例是当你需要在两个变量之间交换值时:
Python
>>> a = 5
>>> b = 10
>>> a, b = b, a
>>> a
10
>>> b
5
a在突出显示的行中,您交换和的值,b而不使用临时变量,如前所述。在此示例中,请务必注意等号右侧的可迭代对象是变量元组。
赋值表达式
赋值表达式允许您一步将条件或循环中使用的表达式的结果分配while
给名称。例如,考虑以下循环,该循环从键盘获取输入,直到您键入单词"stop"
:
Python
>>> line = input("Type some text: ")
>>> while line != "stop":
... print(line)
... line = input("Type some text: ")
...
Type some text: Python
Python
Type some text: Walrus
Walrus
Type some text: stop
此循环按预期工作。但是,此代码有一个缺点,即它不必要地重复调用input()
。
您可以使用赋值表达式重写循环并得到以下代码:
Python
>>> while (line := input("Type some text: ")) != "stop": ... print(line)
...
Type some text: Python
Python
Type some text: Walrus
Walrus
Type some text: stop
在表达式中(line := input("Type some text: "))
,您创建了一个名为的新变量line
来保存对输入数据的引用。此数据也作为表达式的结果返回,最终将其与单词进行比较"stop"
以完成循环。因此,赋值表达式是创建变量的另一种方式。
理解变量作用域
作用域的概念定义了如何在代码中查找变量和名称。它决定了变量在代码中的可见性。变量的作用域取决于在代码中创建变量的位置。
在 Python 中,您可能会发现最多四种不同的作用域,它们可以使用LEGB首字母缩写词表示。该首字母缩写词中的字母代表本地、封闭、全局和内置作用域。
在以下部分中,您将学习 Python 中变量范围的基础知识以及这个概念如何影响您使用变量的方式。
全局、局部和非局部变量
全局变量是您在模块级别创建的变量。这些变量在包含模块和导入它们的其他模块中可见。因此,例如,如果您使用 Python REPL,则当前全局范围在名为 的模块中定义__main__。
此模块定义您当前的全局范围。此模块中定义的所有变量都是全局的,因此您可以在交互式会话运行期间随时使用它们:
Python
>>> value = 42
>>> dir()
[
'__builtins__',
'__doc__',
'__loader__',
'__name__',
...
'value' ]
在此代码片段中,您定义value
变量并调用内置dir()函数来检查当前全局范围内定义的名称列表。在列表末尾,您将找到'value'
与您的变量相对应的条目。
现在,假设您使用同一个交互式会话运行几段代码,同时尝试 Python 的一些很酷的功能。在完成所有这些示例之后,您需要value
再次使用该变量:
Python
>>> value
42
您会注意到变量仍然可用。这是因为该value
变量对于您的代码来说是全局的。
您还可以使用语句导入当前模块之外定义的变量import
。这种做法的一个典型示例是当您有一个模块定义一个变量来保存一些配置参数时。您可以将此变量导入到全局范围并像使用任何其他全局变量一样使用它。
举一个简单的例子,假设您有以下config.py
模块:
Python
settings = {
"background": "black",
"foreground": "white",
"logo": "logo.png",
"font": "Helvetica",
}
此文件定义了一个字典,其中包含假设应用程序的几个配置参数。您可以将此变量导入到应用程序的全局范围,并根据需要使用设置参数:
Python
>>> from config import settings
>>> settings["background"]
'black'
>>> settings["font"]
'Helvetica'
通过第一行中的导入,您已将settings
变量带入当前全局范围。您可以在代码的任何部分使用该变量。
局部变量是您在函数内部定义的变量。这些变量可以帮助您将中间计算的结果存储在描述性名称下。它们可以使您的代码更具可读性和明确性。
请考虑以下示例:
Python
>>> def function():
... integer = 42
... return integer
...
>>> function()
42
>>> integer
Traceback (most recent call last):
...
NameError: name 'integer' is not defined
局部变量仅在其定义函数内可见。一旦函数返回,变量就会消失。这就是为什么您无法integer
在全局范围内访问。
类似地,非局部变量是你在定义内部函数的函数中创建的变量。外部函数的局部变量对内部函数来说是非局部的。创建闭包函数和装饰器时,非局部变量很有用。
下面是一个玩具示例,说明了全局、局部和非局部变量如何工作以及如何识别 Python 中的不同范围:
Python
# Global scope
global_variable = "global"
def outer_func():
# Nonlocal scope
nonlocal_variable = "nonlocal"
def inner_func():
# Local scope
local_variable = "local"
print(f"Hi from the '{local_variable}' scope!")
print(f"Hi from the '{nonlocal_variable}' scope!")
print(f"Hi from the '{global_variable}' scope!")
inner_func()
在此示例中,您首先在模块级别创建一个全局变量。然后,定义一个名为 的函数outer_func()
。在此函数内部,您有nonlocal_variable
,它是 的局部变量outer_func()
,但不是 的局部变量inner_func()
。
在 中inner_func()
,您创建另一个名为 的变量local_variable
,该变量是函数本身的局部变量。
注意:您可以在内部函数中访问全局变量和非局部变量。但是,要从内部函数中更新全局变量或非局部变量,您需要明确使用global 和 nonlocal语句。
这些调用print()旨在展示如何在函数内部访问来自不同范围的变量。
该函数的工作原理如下:
Python
>>> from scopes import outer_func
>>> outer_func()
Hi from the 'local' scope!
Hi from the 'nonlocal' scope!
Hi from the 'global' scope!
总之,全局变量可从代码中的任何位置访问。局部变量在其定义函数中可见。非局部变量在其定义或封闭函数中以及封闭函数中的任何内部函数中可见。
类和实例变量(属性)
使用面向对象编程工具时,您可以在自定义 Python 类中创建变量。这些变量称为属性。实际上,您可以拥有类和实例属性。
类属性是您在类级别创建的变量,而实例属性是附加到给定类的实例的变量。这些属性仅在类或其实例内可见。因此,类定义了一个命名空间,它类似于作用域。
为了说明类和实例属性的工作原理,假设您需要一个类来表示公司的员工。该类应保存有关员工的信息,您可以将这些信息存储在实例属性中,例如.name
、.position
等。该类还应记录公司目前有多少名员工。要实现此功能,您可以使用类属性。
以下是您的课程的可能实现:
Python
class Employee:
count = 0
def __init__(self, name, position, salary):
self.name = name self.position = position self.salary = salary Employee.count += 1
def display_profile(self):
print(f"Name: {self.name}")
print(f"Position: {self.position}")
print(f"Salary: ${self.salary}")
在这个Employee
类中,您定义一个名为的类属性count
并将其初始化为0
。您将使用此属性作为计数器来跟踪Employee
实例的数量。类属性(如).count
对于该类及其所有实例都是通用的。
在初始化程序中,.__init__()
您定义了三个实例属性来保存员工的姓名、职位和薪水。 中的最后一行代码会.__init__()
在每次创建新员工时将计数器增加1
。为此,您可以访问类对象本身的类属性。
注意:您无法使用self对象更改类属性的值。例如,如果您执行类似self.count += 1而不是 的操作Employee.count += 1,则会创建一个新的实例属性来遮盖类属性。您也可以使用 而type(self).count不是来访问类属性Employee.count。
最后,您有一个方法可以根据员工的当前信息显示员工的个人资料。此方法表明您需要使用self
参数来访问类中的实例属性。
以下是如何在代码中使用此类的方法:
Python
>>> from employees import Employee
>>> jane = Employee("Jane Doe", "Software Engineer", 90000)
>>> john = Employee("John Doe", "Product Manager", 120000)
>>> jane.display_profile()
Name: Jane Doe
Position: Software Engineer
Salary: $90000
>>> john.display_profile()
Name: John Doe
Position: Product Manager
Salary: $120000
>>> f"Total employees: {Employee.count}"
'Total employees: 2'
Employee
在此代码中,您首先通过使用适当的参数调用类构造函数来创建 的两个实例。然后,对两个员工调用显示方法并获取相应的信息。最后,您访问 的.count
属性Employee
以获取当前的员工人数。
值得注意的是,您可以访问实例属性,例如.name
或.position
使用目标实例上的点符号:
Python
>>> jane.name
'Jane Doe'
>>> john.name
'John Doe'
>>> Employee.name
Traceback (most recent call last):
...
AttributeError: type object 'Employee' has no attribute 'name'
实例属性特定于一个实例,因此您无法通过类访问它们。相反,类属性是类及其所有实例所共有的:
Python
>>> jane.count
2
>>> john.count
2
>>> Employee.count
2
要访问类属性,您可以使用实例或类本身。但是,要直接更改类属性,您需要使用该类。继续尝试以下示例:
Python
>>> john.count = 100
>>> john.count
100
>>> Employee.count
2
>>> Employee.count = 100
>>> Employee.count
100
在此示例中,您尝试count
使用实例来更新属性john
。此操作导致您将新实例属性附加到,john
而不是更新的值Employee.count
。要更新类属性,您需要使用类本身。
从作用域中删除变量
在 Python 中,你可以使用以下语句从给定范围显式删除变量或更一般地说名称del
:
Python
>>> city = "New York"
>>> city
'New York'
>>> del city
>>> city
Traceback (most recent call last):
...
NameError: name 'city' is not defined
在此代码片段中,您首先city
在当前全局范围内创建一个名为的新变量。然后,使用该del
语句从其包含范围中删除该变量。当您再次尝试访问该变量时,您会收到NameError
异常。
您应该知道,虽然del
删除了对对象的引用,但它并不一定立即释放内存。一旦不再有对该对象的引用,Python 的垃圾收集器就会回收内存。
最后
现在,您已经了解了在 Python 中使用变量的基础知识,包括如何在代码中创建和使用变量。您已经了解到,Python 变量可以在不同时刻指向不同数据类型的对象,这使得 Python 成为一种动态类型语言。
您还学习了如何在表达式和其他常见用例(如计数器、累加器和布尔标志)中使用变量。此外,您还探索了命名变量的最佳实践。
在本教程中,您已经:
有了这些技能,您现在可以自信地管理 Python 程序中的数据,编写可读且可维护的代码,并应用最佳实践来确保代码的质量。
本文的PDF格式文章已经上传到CSDN VIP资源库中,有兴趣的可以下载保存
作者:潜洋