python-标识符、变量、引用、深浅拷贝

本文介绍的是python的基础:先从定义名称 来说 标识符 --> 变量 -->引用--> 深浅赋值

标识符

Python 对各种 变量方法函数 等命名时使用的字符序列称为标识符。

也可以说凡是自己可以起名字的地方都叫标识符。

标识符就是一个名字,它的主要作用: 变量、函数、类、模块 以及其他对象的名称。

Python标识符的命名规则

  • Python 由 26 个英文字母大小写,0-9 ,_ 组成。

  • Python 不能以数字开头。

  • Python 严格区分大小写。

  • Python 不能包含空格、@、% 以及 $ 等特殊字符。

  • 不能以系统保留关键字作为标识符(一共有25 个)。

Python标识符的命名注意事项

  • 尽量采取有意义的包名,简短,有意义,不要和系统保留关键字冲突。

  • 以单下划线开头的标识符,表示不能直接访问的类属性,其无法通过 import 的方式导入。

  • 以双下划线 开头的标识符 表示 的私有成员。

  • 以双下划线作为 开头和结尾的标识符,是专用标识符。

  • Python 标识符是允许使用汉字作为标识符的。

Python标识符规范

  • 当标识符用作模块名时,应尽量短小,并且全部使用小写字母,可以使用下划线分割多个字母。

  • 当标识符用作包的名称时,应尽量短小,也全部使用小写字母,不推荐使用下划线。

  • 当标识符用作类名时,应采用单词首字母大写的形式。

  • 模块内部的类名,可以采用 “下划线+首字母大写” 的形式。

  • 函数名、类中的属性名和方法名,应全部使用小写字母,多个单词之间可以用下划线分割。

  • 常量命名应全部使用大写字母,单词之间可以用下划线分割。

总结

对各种变量、方法、函数等命名时使用的字符序列称为标识符。

由 26 个英文字母大小写,0-9 ,_ 组成,不能以数字开头,且严格区分大小写。

不能包含空格、@、% 以及 $ 等特殊字符,不能以系统保留关键字作为标识符(一共有25 个)。

Python 中,以下划线开头的标识符有特殊含义。

变量

概念

  1. 首先他是弱类型语言 ,在Python中,变量是没有类型的

  1. 在使用变量的时候,不需要提前声明,只需要给这个变量赋值即可。

但是,当用变量的时候,必须要给这个变量赋值;如果只写一个变量,而没有赋值,那么Python认为这个变量没有定义。

变量的类型:

Number

数字

String

字符串类型

Tuple

元组

List

列表

Set

集合

Dictionary

字典

变量无类型,对象有类型

总结来说:在Python中,类型是属于对象的,而不是变量,

变量和对象是分离的,对象是内存中储存数据的实体,变量则是指向对象的指针。

引用

引用的概念

python中所谓的赋值: 其实传的是对象指向的引用,也就是说传的是地址。

任何一个python对象都有标签,类型和值三个属性。

  • 标签在对象创建后 直到内存回收就保持不变,可以理解为内存地址。

  • python在给变量赋值,会把赋值的对象的内存地址赋值给变量,也就是说python的变量是地址引用式的变量。

  • 引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的值本身。

  • 可以通过is或者比较id()的判断是否引用的是同一个内存地址的变量。

== 是比较两个对象的内容是否相等,即两个对象的值是否相等
is同时检查对象的值和内存地址。可以通过is判断是否是同一个对象
id() 列出变量的内存地址的编号

引用同时要考虑 对象的因素

python中的一切都是对象。对象: 又分为可变对象和不可变对象。

二者的区别在于对象的值在不改变内存地址的情况下是否可修改。

可变对象包: 字典dict、列表list、集合set、手动声明的类对象等
不可变对象: 数字int float、字符str、None、元组tuple等
list 可变对象,内容变更地址不变
a = [1, 2, 3]
print(id(a))
a.append(5)
print(id(a))

不可变对象(常用的共享地址或缓存)# 较小整数频繁被使用,python采用共享地址方式来管理
a = 1
b = 1
print(a is b) # True

# 对于单词类str,python采用共享缓存的方式来共享地址
a = 'hello'
b = 'hello'
print(a is b) # True

不可变对象(不共享地址)
a = (1999, 1)
b = (1999, 1)
print(a is b) # False

a = 'hello everyone'
b = 'hello everyone'
print(a is b) # False

元组的相对不可变型
# 元组的里元素是可变,改变可变的元素,不改变元组的引用
a = (1999, [1, 2])
ida = id(a)
a[-1].append(3)
idb = id(a)

print(ida == idb) # True

这里之提到变量可变和不可变的特性

主要想说的是: 1. 变量的引用:和 变量可变、不可变没有直接的关系。

2. 是变量 可不可以修改,注意这个修改不是通过赋值的操作来完成。

# 前后两个变量a, 已经不是同一个地址了
a = [1, 2, 3]
print(id(a))
a = a + [5]
print(id(a))

函数参数的引用

函数的传参方式是共享传参,即函数的形参是实参中各个引用的副本(别名)。

函数会修改是可变对象的实参(表示的同一个对象);而不会改变实参的引用。

def func(d):
    d['a'] = 10
    d['b'] = 20 # 改变了外部实参的值
    d = {'a': 0, 'b': 1} # 赋值操作, 局部d贴向了新的标识
    print(d) # {'a': 0, 'b': 1}
d = {}
func(d)
print(d) # {'a': 10, 'b': 20}

建议不要写上面例子的代码,局部变量和全局变量的名称一样,尽量编码,否则很容易出bug而不自知。

函数的参数的 默认值避免使用可变参数,尽量用None来代替。原因是函数的默认值是作为函数对象的属性,如果默认值是可变对象,而且修改了它,那边后续的函数对象都会受到影响。

深浅赋值【拷贝】

由上面的顺下来就可以看出值的引用,由此可以引出深浅赋值的概念。

浅拷贝和深拷贝

对于可变对象,我们要时刻注意它的可变性,特别是对赋值或者拷贝后的变量做内容修改操作的时候,需要考虑下是否会影响到原始变量的值,如果程序有bug,可以往这方面想一想。这里讲一下拷贝即建立副本。拷贝有两种:

dict1 =  {'user':'runoob','num':[1,2,3]}
 
dict2 = dict1          # 浅拷贝: 引用对象
dict3 = dict1.copy()   # 浅拷贝:深拷贝父对象(一级目录),子对象(二级目录)不拷贝,还是引用
 
# 修改 data 数据
dict1['user']='root'
dict1['num'].remove(1)
 
# 输出结果
print(dict1)
print(dict2)
print(dict3)

实例中 dict2 其实是 dict1 的引用(别名),所以输出结果都是一致的,dict3 父对象进行了深拷贝,不会随dict1 修改而修改,子对象是浅拷贝所以随 dict1 的修改而修改。

{'num': [2, 3], 'user': 'root'}
{'num': [2, 3], 'user': 'root'}
{'num': [2, 3], 'user': 'runoob'}

copy和deepcopy均是开辟了新的内存空间

不可变对象的话因为是拷贝值, 所以原被拷贝对象中不可变对象的变化并不会影响到拷贝后的对象.

浅拷贝:copy

浅复制的值:不可变对象: int、tuple、str、bool

两者中的元素具有相同的内存地址。对象的id值与浅复制原来的值相同。

>>> a="1234567"
>>> b=a                  # 对不可变对象的引用
>>> id(a)4367619440      # 两者中的元素具有相同的内存地址
>>> id(b)4367619440      # 两者中的元素具有相同的内存地址

>>> c=copy.copy(a)
>>> id(c)4367619440   # 两者中的元素具有相同的内存地址

>>> d=copy.deepcopy(a)
>>> id(d)4367619440   # 两者中的元素具有相同的内存地址
当浅复制的值是可变对象
第一种情况:浅复制的值是可变对象(列表,字典)时,改变的值不是 复杂子对象

原值的改变 ---- 不会影响浅复制的值,

浅复制的值改变----不会影响原来的值。

原值的id值----浅复制的原值----不同。

>>> l1=[1,2,3]
>>> l2=l1              # 对可变对象的引用
>>> id(l1)
4367654664            # 原来值的ID 
>>> id(l2)            # l1 和 l2 两者中的元素具有相同的内存地址
4367654664            

>>> l1.append(55)       #  原来的值   
>>> print(l1)           #  原来值的改变
[1, 2, 3, 55]        

l3=copy.copy(l1)    #  不会影响浅复制的值,同时浅复制的值改变也并不会影响原来的值

>>> id(l3)
4367628616           # 原来值的id值与浅复制 的ID不同。

>>> print(l3)  
[1, 2, 3]
第二种情况:复制的对象中有 复杂 子对象 (例如 列表中的一个子元素是一个列表)
  • 不改变其中复杂子对象,改变原来的值 并不会影响 浅复制的值

  • 改变原值 中的复杂子对象的值 会影响浅复制的值。

当浅复制的值是可变对象(列表,字典)时,改变的值是 复杂子对象

>>> import copy
>>> list1=[1,2,['a','b']]   # 复制的对象中有 复杂 子对象  一个子元素是一个列表
>>> list2=list1
>>> id(list1)
4338414656                # l1 和 l2 两者中的元素具有相同的内存地址
>>> id(list2)
4338414656
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
list3=copy.copy(list2)
>>> id(list3)
4338415016                # l3 和 l2 两者中的元素有不相同的内存地址
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>> list1[2].append('a')    # 改变原来的值 中的复杂子对象的值
>>> id(list1)
4338414656
>>> print list1
[1, 2, ['a', 'b', 'a']]

>>> print list3            # 会影响浅复制的值。
[1, 2, ['a', 'b', 'a']]
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>> list1.append(33)      # 改变原来的值
>>> id(list1)
4338414656
>>> id(list3)
4338415016                # 不会影响浅复制的内存地址。
>>> print list1
[1, 2, ['a', 'b', 'a'], 33]
>>> print list3           # 不会影响浅复制的值。
[1, 2, ['a', 'b', 'a']]

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

深拷贝 deepcopy

定义

深复制,被复制对象完全再复制一遍作为独立的新个体单独存在。所以改变原有被复制对象不会对已经复制出来的新对象产生影响。

总结

  • a b是不相同的内存地址,

  • ab中的元素内存地址也不相同,两者完全独立。

  • a中的可变对象发生改变的话不会影响b中对象的改变。

list1=[1,2,['a','b']]             # 原地址
>>> id(list1)
4338414656    

list3=copy.copy(list2)           # 浅复制
>>> id(list3)
4338415016    

list4=copy.deepcopy(list3)       # 深复制
>>> id(list4)
4338414368                        # 不会影响深复制的内存地址。 因为是新开的 两者完全独立。

>>> print list4
[1, 2, ['a', 'b']]

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>> list1.append(33)              # 改变原来的值
print list1
[1, 2, ['a', 'b', 'a'], 33]

list1[2].append('a')            # 改变原来的值 中的复杂子对象的值
>>> print list1
[1, 2, ['a', 'b', 'a']]

 print list4
[1, 2, ['a', 'b']]            # 可变对象发生改变的话不会影响b中对象的改变
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值