关于Python中的基础问题与重点语法分析
Posted huhuhuqaq
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Python中的基础问题与重点语法分析相关的知识,希望对你有一定的参考价值。
目录
身为一个python小白,在不懈的学习了快两个月python后,已经基本学完了python的基础语法,在学习中也遇到了很多坑,现在我希望把我遇到的坑分享一下,也是关于一些基础问题,希望对刚开始学习的小伙伴可以有所帮助。同时里面也有几个python里的高级语法和难理解的概念,这里面本身也包含我自己不理解的一些点,我抱着尝试的心去讲一下,要是对里面的一些代码或者专业词汇描述有错或者讲错的话,还请专业人士指正。
一、pycharm的使用问题
相信很多人在学习的时候都下载了pycharm,身为python的一个集成开发环境,pycham我觉得编程环境是最好的。除此之外我也试过vs vscode等,但我觉得都没有pycharm好用。
1、在pycharm上我建议下载tabnine的代码补全和汉化(汉化根据个人需要,要是英语特别好或者后期其实不用汉化,甚至用起来会很别扭)
2、pycharm不同于IDLE,IDLE上使用print或者直接敲回车都可以实现输出,但是pycharm上必须是要加一个print的,例如这样一个查找索引值的代码和布尔类型,在IDLE中直接敲回车就可以实现,但是pycharm中的print必不可少
a=["1","2"]
print("1" in a)
print(a.index("1"))
3、pycharm最人性话的设计可能是每日小技巧了,他会每天根据你敲的代码来给你一点小技巧使你更方便,但是这在汉化之后也也是英文显示,但是还是建议直接耐心翻译去看一下。
二、首行缩进
这是我碰到的最难受的一个点了,有的时候你首行缩进错了pycharm并不会报错,但是会让你得到不是你想要的东西,有的时候也会大片的报错。
而我总结了一下,主要就是逻辑问题,写程序时候的逻辑不能错,这件事干完该干什么,是并列还是包含,只要把本质弄清楚,就不会错
1、if else elif 这是最基础的但也是在逻辑上最容易出错的,我就从我直接做的一些作业来说,例如我在之前学完循环语句和条件语句做的一个小作业,要让打印一个购物车的程序,循环打印商品列表
product=[["iphone",111],["xiaomi",222],["huawei",333]]
shopping_cart=[]
while True:
print("-----商品列表--------")
for index,i in enumerate(product):
print("%s.%s %s"%(index,i[0],i[1] ))
choice = input("输入你想买的东西的编号:")
if choice.isdigit():
choice=int(choice)
shopping_cart.append(product[choice])
print("Add product %s into shopping cart."%(product[choice]))
elif choice=="q":
print("-----你已经购买以下商品-----")
for index,p in enumerate(shopping_cart):
print("%s. %s %s" % (index,i[0],i[1]))
尤其是中间,在中间开始循环之后,利用for循环和enumerat函数将商品产生出索引值以后,if语句跟for循环是并列的,而不能将if和elif缩进进去,这样才能使if语句有效,且在elif语句输入q退出时,另一for也必须在elif语句里面这样才能退出并打印已经加入的商品列表
2、函数类与面向对象的缩进,这两者中的语法显然比缩进重要,但是在这里也提一下,以这样的一段嵌套为例
age=19
def k1():
age = 73
print(age)
def k2():
print(age)
k2()
k1()
调用参数位置的不同也能影响输出的结果,类与面向对象与函数相似,在调用与实例化的时候也需要注意。
注:主要在函数以及面向对象中,会出现嵌套函数以及多态问题,进而对逻辑有了更大的要求。
三、深浅copy
这算是python里面比较难理解的一个点,容易在考试里面出到,我们先从这样一段代码然后逐步加深理解
>>>a=1
>>>b=a
>>>a=2
>>>b
1
>>>id(a)
>>>id(b)
在这段代码里,你要是输出b的值你会发现会输出1,因为在b=a以后,b指向了1,而并不是指向a,所以b并不会跟随a改变,可以用最后两行代码来验证一下他们的内存地址(下面的代码相当于我在IDLE里面写的)
现在我们在列表里来看一下这段代码
>>>n1=["hu","wang","iphone",1,2]
>>>n2=n1
>>>n2
["hu","wang","iphone",1,2]
>>>n1[2]="huawei"
>>>n1=["hu","wang","weawei",1,2]
>>>n2
大家想一想,我此时输出n2会发生什么,按照上面的理解,n2是不会跟着n1改变的,但是他输出的结果和改变后的n1是一样的,这是为什么,就像我把一个东西放到杯子里面,每一个东西就是一个内存地址,现在n2直接指向了n1的内存地址,相当于n2,n1完全相同,对这两个列表进行增删查改,这两个列表也仍然相同
但是如何将这两个列表独立呢,这是用copy可以实现
>>>n1=["hu","wang","iphone",1,2]
>>>n2=n1.copy()
>>>n1,n2
>>>(['hu', 'wang', 'iphone', 1, 2], ['hu', 'wang', 'iphone', 1, 2])
用两种方法可以检验一下是否独立,检验内存地址和改值
>>>n1=["hu","wang","iphone",1,2]
>>>n2=n1.copy()
>>>n1,n2
>>>(['hu', 'wang', 'iphone', 1, 2], ['hu', 'wang', 'iphone', 1, 2])
>>>id(n1)
2998395112000
>>>id(n2)
2998395300480
>>>n1[1]=2
>>>n1
['hu', 2, 'iphone', 1, 2]
>>>n2
['hu', 'wang', 'iphone', 1, 2]
此时会发现,内存地址并不一样并且修改n1后n2也不变,但是这样做又会有一个新问题,比如这样
>>>n1[1]=2
>>>n1
['hu', 2, 'iphone', 1, 2]
>>>n2
['hu', 'wang', 'iphone', 1, 2]
>>>n1.append(["3",3])
>>>n1
['hu', 2, 'iphone', 1, 2,["3",3]]
>>>n1[-1][0]="huhu"
>>>n1
['hu', 2, 'iphone', 1, 2,["huhu",3]]
>>>n2
['hu','wang', 'iphone', 1, 2,["huhu",3]]
大家发现了什么,我在n1这个列表里加了一个列表,不是说已经独立了吗,我在修改了n1这个列表里面的列表,n2也跟着改了。这是为什么,我们所说的独立,是这个列表里面的元素独立了,即是列表里面的列表独立,为什么子列表里面的元素会变,因为子列表的元素都指向一个内存地址即这个子列表。
综上所述
以上都是浅层次的独立了列表,所有叫浅copy,但是如何深copy呢,这是需要导入一个库,当我们导入了copy库以后,便可以完全实现深copy了。
import copy
>>>n1=['hu', 2, 'iphone', 1, 2,["3",3]]
>>>n2=n1.copy()
>>>n2
['hu', 2, 'iphone', 1, 2,["3",3]]
>>>n1[-1][0]="huhu"
>>>n1
['hu', 2, 'iphone', 1, 2,["huhu",3]]
>>>n2
['hu','wang', 'iphone', 1, 2,["3",3]]
四、字符编码
python中的字符编码真的好复杂好复杂,甚至python2和python3也有不同,这里面也涉及到有的时候为什么你输出的结果变成了乱码,我其实也不知道我现在到底理解了没有,但是先讲一下,看看我到底能不能把这个最基本的讲清楚
1、什么是字符编码
学计算机的朋友们应该都知道,计算机只能通过0和1来识别我们的语言,所以字符编码就是将我们的语言全部转为二进制来让计算机去理解
2、一些常见的字符编码
①ASCII
这是美国人发明的包含了最基本的128个字符的编码表,通过这些使计算机可以了解我们的语言,但是这里面是英文字符啊,中国人要是想用怎么办,于是Unicode诞生了
②unicode
Unicode又被称为统一码、万国码;它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
③GB2312与GBK
中国国家标准总局1980年发布《信息交换用汉字编码字符集》提出了GB2312编码,用于解决汉字处理的问题。1995年又颁布了《汉字编码扩展规范》(GBK)。这样就解决了我们国家的编码问题。
④UTF :UTF-8,UTF-16 UTF-32
既然unicode这么好用,为什么不全世界一直用unicode呢,unicode存在这样的一个问题,使用unicode来表示一个字符,至少占两个字节,而ASCII码只需要一个,这样会导致浪费内存空间,所以UTF出现了,UTF就是为unicode编码设计的一种在存储和传输时节省空间的编码方案,可以理解为对unicode的一种压缩,最常用的为UTF-8
UTF-8使用1、2、3、4个字节表示所有字符,无法满足则增加一个字节
3、python2与python3的字符编码
python3字符串默认unicode 而文件默认编码是UTF-8,python2中,文件编码和字符串编码中都为ASCII,若文件头声明gbk,则字符串编码为gbk
4、编码在windows上的显示
这里涉及到你写的程序在终端上的运行,我也还没有学习只是简单了听了一点,例如windows智能显示unicode和gbk,否则会变成乱码。
5、字符编码的转换
你可以通过以下代码来进行字符编码的转换
>>>s="hu"
>>>s2=1.decode("utf-8")
总结:我对于字符编码的理解也只是这些基础知识,这里面有的东西还涉及到终端里的输出 与unicode编码的详解我都不拿出来说了,希望后续可以有大佬来进行详解。
五、闭包函数和装饰器
关于闭包函数和装饰器,这是我讲的唯一一个高级语法,我看了视频里面说这也是在面试里比较容易出到的问题,首先何为装饰器,以我的理解,就是升级你的函数功能,但是,升级函数的方法又很多种,你可以定义多个函数,可以多次调用函数,但是、、、、
第一,有的时候你的代码实现了功能但是却会违反一些原则,例如“开放-封闭”原则:
开放:已实现的功能代码块不能被修改
封闭:对现有的功能进行拓展开发
第二,软件开发需要的是多个团队的运营和调试,包含成千上万的代码,你这边实现了自己的模块,下一组的人呢,或许之后的代码就需要重复修改几千次甚至几万次或者直接报错。现在我以这样的一个功能来一步步进行讲解
比如这样,你的老板要让你将查找数字和记录时间整合到一起,可能你会写出这样一段代码(这里引用了b站up主‘嘉然今晚吃枪子’的讲解视频,想学习的同学也可以去看一下)
import time
def kprint_odds():
start_time=time.perf_counter()
for i in range(100):
if i in range(100):
print(i)
end_time=time.perf_counter()
print("it takes {} s to find all the odds".format(end_time-start_time)
if __name__="__main__"
print_odds()
这一个函数你会发现你成功的实现了功能,但是你会发现一个函数两个辅助功能,有的代码里面或许不止两个辅助功能,万一出错修改非常麻烦甚至影响了主要功能,代码函数一多,这样写函数几乎就是一个灾难,于是我们可以这样修改
import time
def count_time(func):
start_time=time.perf_counter()
func()
end_time=time.perf_counter()
print("it takes {} s to find all the odds".format(end_time-start_time)
def print_odds():
for i in range(100):
if i%2 == 1:
print(i)
id __name__="__main__":
count_time(print_odds)
这样定义两个函数便可以减少错误,但是这样的写法仍有一个缺点,最后是通过在辅助函数里传入主要函数进行运行,语法上可行,在可读性上不好,给读者显示的应该是直接显示主要函数,辅助函数应该被隐藏起来,于是我们就引入闭包函数。
闭包函数:一个函数的参数和返回值都是函数
注:闭包本质上是一个函数
闭包函数的传入参数和返回值也都是函数
闭包函数的返回值函数是对传入函数增强后的结果
import time
def print_odds():
for i in range(100):
if i%2 ==1:
print(i)
def count_time_wrapper(func):
#闭包,用于增强函数func,给函数func增加统计时间的功能
def improved_func():
start_time = time.perf_counter()
func()
end_time = time.perf_counter()
print("it takes {} s to find all the odds".format(end_time - start_time))
return improved_func
if __name__ == "__main__":
#调用count_time_wrapper增强函数
print_odds = count_time_wrapper(print_odds)
print_odds()
print(print_odds())
这是我们手动写了一段增强函数的代码来增强函数功能
print_odds = count_time_wrapper(print_odds)
然而我们需要一种机制,让python解释器自动增强,这时候python装饰器就来了
import time
def count_time_wrapper(func):
def improved_func():
start_time = time.perf_counter()
func()
end_time = time.perf_counter()
print("it takes {} s to find all the odds".format(end_time - start_time))
return improved_func
@count_time_wrapper
def print_odds():
for i in range(100):
if i % 2 == 1:
print(i)
if __name__ == "__main__":
print_odds()
所有python装饰器本质上就是函数闭包,并且装饰器在第一次调用被装饰函数时进行增强。
上面的装饰器你会发现,里面并没有返回值和没有输入参数的,如果我的函数又返回值和输入参数,还能加强吗?
这里需要注意
对于有返回值的函数,调用闭包增强后,不能成功返回,但是增强了函数的辅助功能
import time
def count_time_wrapper(func):
def improved_func():
start_time = time.perf_counter()
func()
end_time = time.perf_counter()
print("it takes {} s to find all the odds".format(end_time - start_time))
return improved_func
@count_time_wrapper
count=0
def count_odds(): #统计计数的个数
for i in range(100):
if i % 2 == 1:
count+=1
return count #这里增加了函数的返回值
if __name__ == "__main__":
print_odds()
对于含有参数的函数,调用闭包增强后,不能成功接收参数
import time
def count_time_wrapper(func):
def improved_func():
start_time = time.perf_counter()
func()
end_time = time.perf_counter()
print("it takes {} s to find all the odds".format(end_time - start_time))
return improved_func
@count_time_wrapper
count=0
def count_odds(lim=1000): #统计计数的个数 这里还增加了参数
for i in range(100):
if i % 2 == 1:
count+=1
return count #这里增加了函数的返回值
if __name__ == "__main__":
print_odds(lim=1000)
但是我们如何让这个闭包接收返回值和参数呢,参考如下代码
import time
def print_odds(lim=10000):
cnt=0
for i in range(100):
if i%2 ==1:
cnt+=1
return cnt
def count_time_wrapper(func):
def improved_func(*args, **kwargs): #增强函数应该吧接收到的所有参数传给原函数
start_time = time.perf_counter()
res=func(*args, **kwargs) #传入参数并记录返回值
end_time = time.perf_counter()
print("it takes {} s to find all the odds".format(end_time - start_time))
return res #返回未增强函数的返回值
return improved_func
if __name__ == "__main__":
print_odds = count_time_wrapper(print_odds)
print_odds(lim=10000)
这样我们便实现了完美的闭包,后面还有多个装饰器的问题,但我就到此为止吧。
总结
在学习完python的基础语法之后,就可以学习网络编程和爬虫了,这又是一个漫长的道路,在编程这条路上,我需要学习的东西还很多很多,并且需要不停学习,充实自己,现在python作为世界第一编程语言,的确有一些地方相对于c和java来说使用非常方便,这是也是我第一次第一次写博客,希望大家可以支持,同时身为智能科学与技术的大一新生,我也希望在编程这条路上我可以一直走下去,不断努力学习
以上是关于关于Python中的基础问题与重点语法分析的主要内容,如果未能解决你的问题,请参考以下文章