变量
1. 什么是变量
变量是内存中某个值的名称,变量的值其实是该值的内存地址,而不是其值/内容。只是直观感觉是内存的值。
另外python是动态语言即一个变量的类型是由其值决定的。python没有像java语言的声明,eg:String name;声明时就指定的变量的类型。
2. 变量的作用是什么?
1. 程序使用的数据,存储在内存中,而变量就代表其中1个数据,变量的值就是该数据的内存地址。即变量是内存地址(数据),直观上看变量就是内存的1个数据。是程序员与内存数据沟通的桥梁。
2. 变量名不仅可以帮助我们记住每个值的含义,还可以帮助我们在程序中引用这些值。
3. 变量的命名(标识符)
3.1 标识符
Python 标识符是用于命名不同程序实体,如变量、函数、类、模块等的名称。以下是 Python 标识符的规定:
-
由连续的数字、字母(大小写都可以)和下划线
_
组成,但是不能以数字开头。即不能包含空格或其他特殊字符,如@
、#
、$
、%
等。 -
Python 是大小写敏感的,因此
hello
和Hello
是不同的标识符。 -
标识符的长度没有限制。
-
避免使用 Python 中的关键字 (reserved words),如
if
、else
、while
、for
、class
、def
等等。Python 中有 33 个关键字,它们是保留的,用于特定的语法和功能目的。
以下是一些符合 Python 标识符规定的示例:
1 hello_world # 只包含字母和下划线的标识符 2 num_123 # 包含数字、字母和下划线的标识符 3 ThisIsCamelCase # 驼峰式命名法的标识符 4 _123test # 以下划线 `_` 开头的标识符
不符合 Python 标识符规定的示例:
1 2cats # 标识符以数字开头 2 my-name # 标识符包含横线 `-` 3 test@you # 标识符包含特殊字符 `@` 4 while = 10 # 标识符是关键字
查看python内置关键字的方法:
1 import keyword 2 3 print(keyword.kwlist)
# 关键字列表 ['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
3.2 标识符命名规范
常见的3种命名风格:
1. 大驼峰:即每个单词首字母大写,eg:ClassName
2. 小驼峰:首字母小写,其他的单词首字母大写,eg:className
3. 下划线(也叫蛇形):全部小写,多个单词之间使用下划线连接,eg:class_name
在满足标识符的基本要求的基础上,团队需要统一风格。建议:
-
变量、函数、类和模块等名称应该清晰地描述它们的用途。要避免使用与 Python 内置函数或关键字相同的名称。
-
避免使用单字符名称:尽量避免使用单字符名称(例如
x
或y
),除非变量的用途非常清晰明确。 -
学习和使用 Python 的内置函数和模块的名称。
-
变量和函数的命名:在 Python 中,变量和函数通常使用小写字母和下划线来命名,例如:
1 my_variable = 42 2 def my_function(): 3 pass
5. 类和异常的命名:在 Python 中,类和异常通常使用首字母大写的驼峰命名法,例如:
1 class MyClass: 2 pass 3 4 class MyCustomException(Exception): 5 pass
6. 模块和包的命名:在 Python 中,模块和包通常使用小写字母和下划线命名,例如:
1 my_module.py 2 my_package/ 3 __init__.py 4 my_submodule.py
7. 常量的命名: 在 Python 中,常量通常使用所有大写字母和下划线命名,例如:
1 MY_CONSTANT = 3.14
8. 私有变量和函数的命名:在 Python 中,私有变量和函数的命名通常以一个下划线作为前缀,例如:
1 class MyClass: 2 def __init__(self): 3 self._my_private_variable = 42 4 5 def _my_private_function(self): 6 pass
但需要注意的是,这并不是真正的私有,而只是一种约定。任何变量和函数都可以从外部访问,因为 Python 没有真正的私有性。
4. python的数据类型
Python 是一种动态类型语言,提供了多种内置的数据类型。以下是 Python 的全部数据类型:
1. 整型 (int)
int 是一种表示整数的数据类型,可以是正数、负数或零。在 Python 中,整数没有长度限制。
1 x = 10 2 y = -5
2. 长整型 (long)
在 Python 2 版本中,long 是一种表示任意大整数的数据类型。在 Python 3 版本中,int 本身就可以表示任意大整数,long 已经被弃用。
3. 浮点型 (float)
float 是一种表示带小数点的实数的数据类型。在 Python 中,float 类型的数值可以使用科学计数法表示。
1 x = 3.1415 2 y = 1.0e-5
4. 复数型 (complex)
complex 是一种表示复数的数据类型,具有实部和虚部。在 Python 中,实部和虚部均为浮点型数值。
1 x = 3 + 4j 2 print(x) # 输出:(3+4j) 4 y = complex(2,-3) 5 print(y) # 输出:(2-3j) 7 y = complex(2,4) 8 print(y) # 输出:(2+4j)
5. 布尔型 (bool)
bool 是一种表示逻辑值 (True 或 False) 的数据类型。在 Python 中,在条件语句、循环和其他操作中使用 bool 值非常常见。
1 x = True 2 y = False
6. 字符串型 (str)
str 是一种表示字符序列的数据类型,可以使用单引号、双引号或者三引号来表示。在 Python 中,字符串提供了一系列的方法来操作字符串数据。
1 x = 'hello' 2 y = "world" 3 z = """this is a 4 multi-line string"""
7. 列表 (list)
list 是一种有序、可变类型的容器,可以包含任何类型的元素。在 Python 中,列表提供了一系列的方法和操作来修改和查询列表数据。
1 x = [1, 2, 3, 4, 5] 2 y = ['apple', 'banana', 'cherry']
8. 元组 (tuple)
tuple 是一种有序、不可变类型的容器,可以包含任何类型的元素。在 Python 中,元组也提供了一些方法和操作来查询元组数据。
1 x = (1, 2, 3, 4, 5) 2 y = ('apple', 'banana', 'cherry')
9. 集合 (set)
set 是一种无序、可变类型的容器,不能包含重复的元素。在 Python 中,集合提供了一系列的方法和操作来查找、添加、删除和修改集合数据。
1 x = {1, 2, 3, 4, 5} 2 y = {'apple', 'banana', 'cherry'}
10. 字典 (dict)
dict 是一种无序、可变类型的容器,包含键值对。在 Python 中,字典提供了一些方法和操作来添加、查询和修改字典数据。
1 x = {'name': 'Alice', 'age': 25, 'email': 'alice@example.com'} 2 y = {1: 'apple', 2: 'banana', 3: 'cherry'}
11. None
在 Python 中,None
是一种单独的数据类型,表示缺失或无值。它通常被用作函数的返回值或作为变量的默认值。虽然它表示缺失或无值,但它本身是一个有效的 Python 对象。因此,可以把 None
看作一种数据类型,但它是一种特殊的数据类型。也可以说,它是一种空类型,因为它不包含任何有意义的值。
1 x = None 2 print(x) # 输出:None
12. 其他
python一切皆是对象,比如函数,不仅仅是一种对象,还是一种数据类型。我们可以把函数赋值给变量,并且可以把函数作为参数传递给其他函数,从而实现函数式编程的思想。
在 Python 中,通过 def
关键字定义的函数被称为用户自定义函数,也可以使用内置函数来创建函数对象。例如,可以使用 lambda
表达式创建匿名函数,并且可以把匿名函数赋值给变量或者传递给其他函数。
由于函数是一种数据类型,所以可以方便地执行很多与函数相关的操作。例如,可以使用 dir()
函数查看函数的属性和方法;可以使用 help()
函数查看函数的帮助文档;可以使用 callable()
函数来检查一个对象是否为可调用对象 (函数)。
可以使用内置函数 compile()
、exec()
和 eval()
来创建函数对象。这三个函数都是用于执行动态代码的函数,它们可以接受字符串类型的代码作为参数,并编译、执行或求值运行这段代码。因此,这三个函数都可以用于创建函数对象。
具体来说:
compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
:将指定的 ASCII 字符串编译为代码对象,并返回该对象。如果要将编译后的代码转换为函数对象,可以通过types.FunctionType()
将其转换。其中,source
参数是要编译的源码字符串,filename
参数可以是字符串,表示代码的文件名,mode
参数可以是字符串,表示编译的模式,可选值为 'exec'、'eval' 和 'single',默认为 'exec'。其他参数一般不需要设置。例如,下面的代码演示了如何使用compile()
创建一个函数对象,并调用该函数:
1 code = 'def hello():\n print("Hello, world!")' 2 compiled_code = compile(code, '<string>', 'exec') 3 exec(compiled_code) 4 hello() # pyCharm会报错,但运行正常。输出:Hello, world!
exec(source, globals=None, locals=None)
:将指定的 ASCII 字符串作为 Python 程序执行,并返回None
。如果要将执行的代码转换为函数对象,可以先使用compile()
函数编译成代码对象,再使用types.FunctionType()
将其转换。其中,source
参数是要执行的源码字符串,globals
和locals
参数分别是全局和局部命名空间。例如,下面的代码演示了如何使用exec()
创建一个函数对象,并调用该函数:
1 code = 'def hello():\n print("Hello, world!")' 2 exec(code) 3 hello() # pyCharm会报错,但运行正常。输出:Hello, world!
eval(expression, globals=None, locals=None)
:求解指定的表达式,并返回该表达式的运算结果。如果表达式是一个函数定义,可以先使用compile()
编译成代码对象,再使用types.FunctionType()
将其转换为函数对象。例如,下面的代码演示了如何使用eval()
创建一个函数对象,并调用该函数:
1 code = 'lambda x, y: x + y' 2 add = eval(code) 3 print(add(1, 2)) # 输出:3
5. 变量的语法
通过赋值操作符 =
来定义变量。具体来说,变量定义语法如下:
变量名 = 值
1. 变量名
必须符合 Python 的标识符规定级命名规范
2.值
是要赋给变量的值,可以是任何合法的 Python 表达式,例如数值、字符串、列表、元组、字典、函数等等。
3. 变量在使用前必须先定义。如果在使用变量之前未定义,Python 解释器将会抛出 NameError
异常。
print(name) # 没有定义name会报如下错 # Traceback (most recent call last): # File "<pyshell#36>", line 1, in <module> # print(name) # NameError: name 'name' is not defined name
# 直接在idle shell输出变量名,会报如下错 # Traceback (most recent call last): # File "<pyshell#37>", line 1, in <module> # name # NameError: name 'name' is not defined
4. 多重赋值语法即同时为多个变量赋值
x, y, z = 1, 2, 3 print(x,y,z) # 输出: 1 2 3
5. 链式赋值语法在一行中为多个变量赋相同的值
x = y = z = 0
6. 变量的分类及其作用域
按照变量的作用域分为:全局变量、局部变量、类变量、实例变量、方法变量
6.1 全局变量
作用域为整个程序(整个程序是说的一个模块)。如果想在函数体、方法体内修改全局变量的值,需要使用global 关键字
6.2 局部变量
只在定义变量的函数或语句块内有效。函数内部的变量使用有两种方式:一种是函数的参数,一种是函数内部定义的变量。这些变量都是局部变量,函数执行完毕后就会自动销毁。
6.3 类变量也叫成员变量
类定义中定义的变量,它是类的一部分,在类中可以定义和使用,被所有类的实例共享类变量。类变量可以被类或者类的实例访问和修改。
6.4 方法变量
是类和类的实例的一部分,只在方法的作用域内生效,方法的参数也是方法变量的一部分。方法变量的生命周期与方法相同,在执行完方法后就会自动销毁。
6.5 实例变量
实例变量定义语法:实例.变量名=变量值
实例变量修改:实例.变量名=变量值
实例变量访问:实例.变量名
# 全局变量
global_var = 10
# 局部变量
def my_func(arg1, arg2):
local_var = 20
print(arg1 + arg2 + local_var)
# 类变量
class MyClass:
class_var = 30
def __init__(self):
self.instance_var = 40
# 方法变量
class MyClass2:
def my_method(self, arg1, arg2):
method_var = 50
print(arg1 + arg2 + method_var)
global global_var # global global_var = 20 此种写法是错误的
global_var = 20 # 在方法内访问或修改全局变量
print(global_var) # 输出20
print(self.instance_var_2) # 输出:我也是实例变量
# 使用
my_func(1, 2) # 输出: 23
print(MyClass.class_var) # 输出: 30
a = MyClass()
print(a.class_var) # 输出: 30
print(a.instance_var) # 输出: 40
b = MyClass()
print(b.class_var) # 输出: 30
print(b.instance_var) # 输出: 40
print()
c = MyClass2()
c.instance_var_2 = "我也是实例变量"
c.my_method(3, 4) # 输出: 57
print(global_var) # 输出: 20
其中,global_var
是全局变量,local_var
是局部变量,class_var
是类变量,instance_var
是实例变量,arg1
和 arg2
是方法变量。全局变量可以在程序的任何地方被访问和修改,局部变量只在函数内部有效,实例变量只能通过实例进行访问,而不同实例中的实例变量是不相同的,类变量在类的所有实例中共享。方法变量只在方法的作用域内有效,对于类和实例来说都是一样的。
7. 变量的内存模型
Python 中的变量和其他编程语言中的变量有些不同,它是一种引用类型的变量。在 Python 中,每个变量都是一个对象的引用,而不是传统意义上的变量。这意味着变量在使用前必须赋值,否则会抛出异常。
在 Python 中,变量有以下特点:
- 变量的赋值会创建对象,并将对象的引用赋值给变量,如果已经存在相同值的对象,就将变量指向现有对象的引用。
- 变量的删除只有在没有对象引用变量时才会释放内存。
- 变量的值可以是数字、列表、元组、字典等各种数据类型。
- 变量的值可以是函数或类等对象,即变量可以指向函数或类,它们就可以像变量一样进行操作、传递和使用。
Python 中变量的内存模型是基于对象引用的,当有变量引用对象时就会创建一个对象,并返回对象的引用。Python 中有一个内存管理模块 gc
,用于自动回收没用到的内存空间,这个模块的实现是基于标记和清理的原理。它通过标记处理机制,把对象分为可达对象和不可达对象。如果一个对象没有被任何引用所指向,就会被当做垃圾进行回收,这样就可以释放内存空间了。
1 a = 10 # 创建整数对象并将引用赋值给变量 a 2 b = a # 变量 b 也引用整数对象 3 c = a # 变量 c 也引用整数对象 4 5 ''' 6 从输出结果a、b、c的id值一样,说明变量a、b、c引用同一个对象(10) 7 ''' 8 print(id(a)) # 140705379382344 9 print(id(b)) # 140705379382344 10 print(id(c)) # 140705379382344 11 12 ''' 13 修改变量a的值,此时a变量的id值就发生了变化,但b、c变量的值没有变化 14 ''' 15 a = 20 # 创建新的整数对象并将引用赋值给变量 a 16 print(id(a)) # 140705379382664 17 print(id(b)) # 140705379382344 18 print(id(c)) # 140705379382344
Python 的内存模型可以分为三个主要部分:命名空间、对象和引用
-
命名空间:是一种将名称和对象关联在一起的系统,储存了变量名和对应的变量值之间的关系。Python 运行环境中有多个命名空间,例如内置命名空间、全局命名空间和局部命名空间等等。
-
对象:是指存储数据的内容,Python 中数据都以对象的形式存在。每个对象都有一个唯一的标识符、类型和值,标识符是一个整数,通过
id()
函数获取;类型是对象的数据类型,可以通过type()
函数获取;值是对象存储的具体数据。 -
引用:是指在 Python 中访问、操作对象的一个标识,可以看作是指向对象内存地址的指针。变量实际上存储的是对象的引用,而不是对象本身。可以使用
id()
函数获取变量的引用地址。
8. 变量作用域链详解及示例
Python 中的作用域链搜索顺序决定了变量的访问顺序。当程序在一个函数中引用某个变量时,Python 会按照下面的顺序从当前作用域开始搜索该变量:
- 当前函数的局部作用域。
- 外层嵌套函数的局部作用域(如果有的话,也叫闭包作用域)。
- 全局作用域:是指在一个模块中定义的变量和函数名称。在 Python 中,每个模块都有自己的全局命名空间,也就是说在每个模块中定义的变量和函数,只在该模块内部任何地方都是可见和可用的。
- 内置作用域:Python 预定义的常用函数和变量都在内置作用域中。
闭包作用域:在函数内部定义函数并返回,内部函数可以访问外部函数的变量,这个作用域就是闭包作用域。
对于每一个作用域,它会先搜索局部作用域,如果没有找到需要的变量,就会向外层作用域继续搜索,直到找到为止。如果所有的作用域都搜索完了还没有找到该变量,就会抛出 NameError
异常。
示例1:局部作用域中的变量
1 def my_func(): 2 x = 10 # 局部变量 3 print(x) 4 5 my_func() # 输出 10
在这个例子中,变量 x
是在函数内部定义的,因此它属于函数的局部作用域。因此,当我们尝试输出 x
的值时,Python 会先从局部作用域开始搜索,找到变量 x
并输出其值为 10。
示例2:全局作用域中的变量
1 x = 10 # 全局变量 2 3 def my_func(): 4 print(x) 5 6 my_func() # 输出 10
在这个例子中,变量 x
是在函数外面定义的,因此它属于全局作用域。当我们尝试输出 x
的值时,Python 会先从函数内部的局部作用域开始搜索,但是在局部作用域中找不到变量 x
。因此,Python 向外层作用域(也就是全局作用域)发起搜索,找到变量 x
并输出其值为 10
示例3:全局作用域和局部作用域
1 x = 10 # 全局作用域 2 3 def foo(): 4 x = 5 # 局部作用域 5 print(x) 6 7 foo() # 输出 5 8 print(x) # 输出 10
述代码中,x
变量在顶层作为全局变量进行定义,foo()
函数内部的 x
变量则属于局部作用域。在函数内部访问变量 x
时,首先会在函数内部搜索局部作用域,然后是全局作用域,因此最终输出的是局部变量 x
的值 5。
示例4:嵌套作用域中的变量
1 def outer_func(): 2 x = 10 # 嵌套变量 3 4 def inner_func(): 5 print(x) 6 7 inner_func() 8 9 outer_func() # 输出 10
在这个例子中,我们定义了两个函数 outer_func()
和 inner_func()
,并在 outer_func()
中定义了变量 x
。当我们在 inner_func()
中引用变量 x
时,Python 会先从 inner_func()
的局部作用域开始搜索,但在局部作用域中找不到变量 x
。因此,Python 向外层作用域(也就是 outer_func()
的局部作用域)发起搜索,找到变量 x
并输出其值为 10。
示例5:闭包作用域
1 def outer(): 2 x = 10 # 闭包作用域 3 4 def inner(): 5 print(x) 6 7 return inner 8 9 x = 20 # 全局作用域 10 foo = outer() 11 foo() # 输出 10
上述代码中,outer()
函数定义内部的 x
变量属于闭包作用域,它可以被 outer()
函数内部定义的 inner()
函数所访问。当 outer()
函数返回 inner()
函数时,它将 inner()
函数和闭包作用域一起返回。在全局作用域中创建变量 x
的值为 20,然后调用 foo()
函数,输出闭包作用域中的变量值 10。
示例6:函数参数的作用域
1 def my_func(x): 2 print(x) 3 4 my_func(10) # 输出 10
在这个例子中,我们定义了一个函数 my_func()
,其参数为 x
。当我们在 my_func()
中引用参数 x
时,Python 会优先从 my_func()
的局部作用域开始搜索,找到参数 x
并输出其值为 10。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!