第二课.Python编程基础(一)

基础语法

注释

#行注释
"""
块注释
"""

代码分隔符 ‘\’

code=\
"""
Python String
"""

转义符(举例):换行符,文本转义

char='\n'#换行
a='I\'m Tzc'#文本转义

使用分号 ‘;’ 可以一行写多行代码
缩进:用于区分不同的块,类似与C语言中的花括号{…}
空行:pass,不执行,为了满足语法结构

#缩进
title="my title";score=61
if title=="my title":
    print("Welcome")
    if score>=60:
        print("PASS")
    else:
    	pass

表达式与声明

statement声明
一种是赋值,a=“www.baidu.com”;b=100
另一种是创建函数与类,如def…,class…
expression表达式,是一种可返回结果的式子
扩展:exex()可执行声明语句
eval()可执行表达式

#statement声明
a="www.baidu.com"
b=66
def func():
    pass
class obj(object):
    pass
#expression表达式
b+100

#exec()执行声明语句
str1=input()
#>a='python'
exec(str1)
#>a
#'python'

#eval()执行表达式
str2='a'
eval(str2)
#'python'

关键字与合法标识符

关键字:由python保留,不可用于声明,查看关键字可以使用kwlist

import keyword
print(keyword.kwlist)

合法标识符:可赋值的标识符,不能是关键字,且不能以数字开头,当然也不能与内置电池的对象重名,虽然是这样规定,但在python里还是全靠自觉。
插入一下:内置电池是一个模块,叫做__builtins__
当dir(__builtins__)时,可以看到熟悉的input(),open()等对象。
fig1
关于命名也有规范,通常变量小写,常量大写,类则使用驼峰命名法,比如BankAccount
python也有自己的标准操作符
对于算数运算符,我们需要知道以下

**求幂
//取商
%取余数

对于比较运算符,我们至少应知道

==仅比较引用对象的值,不比较对象本身
is 比较两者引用的对象本身,即比较内存地址
innot in 是广泛使用的成员运算符

#'=='只比较引用对象的值,不比较对象本身
num1=6
num2=6
if num1==num2:
    print('equal')

#成员运算符
url='www.baidu.com'
if 'baidu' in url:
    print('in True')

关于引用对象,此处也额外提一下,比如之前的赋值或称为标识符的声明,本质并不是赋值,而是为两个对象建立关联,当del后,即解除了这种关联

#对于标识符的声明
num=123456
#>num
#123456
#本质不是赋值,是将对象123456与对象num建立了关联,del可解除关联
del num
#>num
#name num is not defined

扩展:关键字is
在上面说到’==‘是单纯比较值,这个好理解,而对于’is’(比较内存地址),会出现一些奇怪现象:

>>> num1=6
>>> num2=6
>>> num1 is num2
True #num1和num2是两个不同的对象,为什么会指向同一地址?
>>> str1=123456789
>>> str2=123456789
>>> str1 is str2
False #为什么这里就又符合我们的原始理解了?
>>> str1==str2
True

说实话,第一次我也很迷惑,但了解原因后就明白了,为了节省开销,当值比较小时,可以用一个单位字节存储,num1和num2指向放在缓存池下的同一个地址,即num1指向的6和num2指向的6是同一个对象;当值较大时,为了不易出错,将会把这个值重新申请一块内存区域,并与标识符建立关联,此时str1指向的123456789和str2指向的123456789已经是两个不同的对象,地址当然也不同

赋值或声明标识符

把赋值单独提出来,是因为有些细节容易被忽略,直接看下文实例体会:

#多重赋值
a=100;b=100
a=b=100
#多元赋值
a,b,c=100,200,300
#交换赋值,不需要中间变量temp
a,b=1,2
a,b=b,a
#unpack解包
li=[1,2,3,4,5,'6']
a,b,c,d,e,f=li
print(a,b,c,d,e,f)
#>1,2,3,4,5,'6'

#用逗号的解包
li=[[1,2,3]]
b,=li
#>b
#[1,2,3]

#*号收集规则
a,*b,c=li
print(a,b,c)
#a,c分别接收首个和最后一个元素,其余给b

另一种特别的创建变量方式是通过命名空间实现,命名空间是python各种对象的容器,命名空间本身是一个字典,局部的函数或类的命名空间为locals(),全局的命名空间为globals()
fig2
通过向字典直接创建变量有

globals()['param']=6

看出多了一个对象param,值为6
fig3
扩展部分:从上面看来,对象将会存在于命名空间和内置电池中,因此在操作对象时会有一个搜索顺序,locals()->globals()->内置电池
当在内置电池中创建变量param:__builtins__.param='value'
在上文中,我们已经在globals()中添加了param,现在我们del它:del param
fig4
’value‘这个值还是存在,原因是del param操作先从globals()空间搜索param,由于刚刚已经在globals()中创建过param,值为6,因此直接解除引用,此时内置电池中的param就被保留了下来

Python的对象分类

linux一切皆文件,python一切皆对象
python的对象分两类,不可变对象(数字和字符串),可变对象(列表,字典,元组等)
对于数字,在有时会遇到无穷大的表示:

float('inf') #无穷大
float('-inf') #负无穷大

特别的,在数字上,python支持复数类型:
fig6

数组和字符串(本质还是数组)的访问也有细节:左闭右开
在切片访问中,格式为array[start:end:step]
fig5
所谓左闭右开实际上指end切片截至到end-1处,另外如果索引为负数,代表倒序访问,最后一个用-1表示:

>>> arr[-1]
4
>>> arr[-2]
3

插入一个小细节:python中的[:-1]和[::-1]


首先,我们知道,数组切片格式为[start : end : step],有时会看到[:-1]和[::-1]这种奇怪的表达。首先需要知道,step可省略,默认为1,start和end是可以省略的:
当step为正数时,如果省略start,则默认start为0,如果省略end,则默认end为len(数组对象);
当step为负数,如果省略start,则默认start为-1,如果省略end,则默认end为-len(数组对象),且此时将遵循左闭右闭原则;
因此,[:-1]代表从start访问到-1的前一个(因为左闭右开原则),[::-1]代表倒序访问,[:]代表从头到尾访问一遍
举例如下:

>>> a='python'
>>> a[:]
'python'
>>> a[:-1]
'pytho'
>>> a[1::-1]
'yp'
>>> a[::-1]
'nohtyp'

对于可变对象,先从数组开始,数组的元素类型必须是相同的;
元组是只读的列表,当然,如果turple内某个元素是可以修改的,比如列表,此时元组依然表现得‘可修改’,也许是这个原因,元组就成了可变对象;
集合是无序,元素不重复的对象,由于无序,集合不能用索引访问,如果集合元素是数字时,还是可以用frozenset()进行形式上排序;
字典是由二元关系{K:V}构成的集合,回顾集合,集合就像是只有key的字典;
关于字符串的编码有一个扩展:在python2中,字符串用unicode编码,这是只有python可懂的编码方式,到python3后统一使用utf-8编码,utf-8是更可靠的编码,因为它是计算机本身的一种编码,减少了机器与python交流的出错率。

拷贝和普通赋值

经常遇到深拷贝,浅拷贝之类的事情,这里单独总结一下:
直接赋值=:创建引用,为对象加个别名;
浅拷贝:只拷贝父对象,子对象级别变化后,浅拷贝结果也会变化;
深拷贝:彻底拷贝父子级别的对象;

>>> a=[1,2,3,[4,5,6]]
>>> b=a
>>> import copy
>>> c=copy.copy(a)
>>> d=copy.deepcopy(a)
>>> a[3].append(7)
>>> b
#由于只是别名,对象的head指针没变,子对象变化,b也变化
[1, 2, 3, [4, 5, 6, 7]]
>>> c
#拷贝了父级别的对象,变换的是子对象,所以c也要变化
[1, 2, 3, [4, 5, 6, 7]]
>>> d
#拷贝到父子级别,相当于重新开辟内存全部复制一份副本
[1, 2, 3, [4, 5, 6]]
>>> a=[1,2,3]
>>> b
#a已经更换了对象,这不会影响到b,因为b指向的是head指针,而不是a
[1, 2, 3, [4, 5, 6, 7]]

从上面看可能会觉得普通赋值与浅拷贝没有区别,下面进行区分:

>>> a=[1,2,3]
>>> b=a
>>> a.append(6)
>>> b
#head指针还是一致,原对象改变,b也改变
[1, 2, 3, 6]
>>> c=copy.copy(a)
>>> a.append(7)
>>> c
#区别就在这,当a继续从父对象级别变化时,浅拷贝的结果并不会变,但普通赋值会改变
[1, 2, 3, 6]

可以验证一下普通赋值中head指针的正确性:

>>> b
[1, 2, 3, 6, 7]
>>> a
[1, 2, 3, 6, 7]
>>> b.append(8)
>>> a
[1, 2, 3, 6, 7, 8]

由于b和a指向同一个对象,从b的角度改变对象,发现a也改变了

列表生成式

列表生成式是一种简便的生成列表做法。分三个步骤:

li=[x for x in range(30) if x%3==0]

第一步:for x in range(30)
第二步:if x%3==0
第三步:li=[x]
这里再顺便一提:字典推导式

#字典推导式,其实和列表生成式类似
string='i like python'
strdic={
    
    key:item for key,item in enumerate(string)}

结合列表生成式与数组切片,用一行代码将句子里每个单词的字母进行倒序排列:‘I like python’–>‘I ekil nohtyp’

[elem[::-1] for elem in 'I like python'.split(' ')]

猜你喜欢

转载自blog.csdn.net/qq_40943760/article/details/109114140