python中的这些坑,早看早避免。python
说一说python中遇到的坑,躲坑看这一篇就够了面试
def foo(num,age=[]):
age.append(num)
print("num",num)
return age
print(foo(1))
print(foo(2))
print(foo(3))
复制代码
上面的代码输出的结果并非咱们预期的那样,打印出三个数组[1],[2],[3]。
而是下面这样.数组
num 1
[1]
num 2
[1, 2]
num 3
[1, 2, 3]
复制代码
为何会这样呢,缘由就是参数age是一个列表,列表是一个可变对象,同时在做为函数参数时,至关于全局变量,在函数预处理时就已经分配了内存空间。那么咱们如何修改呢?
其实很简单只要不让列表参数做为列表,通常可变类型对象做为参数的时候默认都是给定None,而后根据对象判断是否为空,若是为空再去定义成列表,修改以下:bash
def foo(num, age=None):
if not age:
age = []
age.append(num)
print("num", num)
return age
print(foo(1))
print(foo(2))
print(foo(3))
复制代码
在刷pythontip的时候遇到这道题,以为颇有必要和你们普及下for。。else的用处,好了下面咱们开始:
输出100之内的全部素数,素数之间以一个空格区分(注意,最后一个数字以后不能有空格)。微信
#在通常领域,对正整数n,若是用2到根号N之间的全部整数去除,均没法整除,则n为质数又叫素数。
import math
num = [] #存放1-100之间的素数
for i in range(2, 100):
for j in range(2, int(math.sqrt(i)) + 1):
if i % j == 0:
break
else:
num.append(i) #根据定义若是都没法正常才加入
for index, i in enumerate(num):
if index == len(num) - 1:
print(i)
else:
print(i, end=" ")
复制代码
根据关键语句「全部整数去除,均没法整除,则n为质数又叫素数。」,转化成程序也就是说在全部的的数字都循环完了,还不能出才做为质数,也就是最后的那个else,体现了这句话。由此能够看出for。。else仍是挺重要的。闭包
看下面的代码,猜测输出结果:app
a = {}
a[1] = "A"
a[1.0] = "B"
a[2] = "C"
print(a)
复制代码
若是不知道字典里的键和hash有关,就不会知道结果是下面这个样子函数
{1: 'B', 2: 'C'}
复制代码
这是为何呢?
由于,Python中的字典是经过检查键值是否相等以及哈希值来肯定两个键是否相同.
具备相同值的不可变对象在Python中始终具备相同的哈希值.
由于
1=1.0
因此hash(1)==hash(1.0).一样的咱们知道python中的true相等,咱们试着
计算其hash值能够看到hash(1)==hash(True)。
由此咱们能够获得以下等式:工具
hash(1)==hash(1.0)==hash(True)
复制代码
由于只不可变对象才存在hash值因此 hash([])不存在。一样咱们能够推断出学习
hash(0) == hash(False) == hash("")
复制代码
根据PEP285中Review部分第6条所述,bool类实际上是从int类继承而来.
print(isinstance(True, int))
复制代码
python3中0=[]=()={}=None=False="",因此当咱们在判断列表,或者字典字符串是否为空的时候不用再使用 a==None,这样的语句了。
a=[]
b={}
c=""
if not a:
print("a不为空")
if not b:
print("b不为空")
if not c:
print("c不为空")
复制代码
通常咱们写if判断的时候,咱们都写成下面这种形式:
if type == "A":
print(1)
elif type == "B":
print(2)
复制代码
像这样的咱们须要写好多重复代码的程序,此时就要考虑是否优化了,针对这种状况咱们能够优先考虑字典。
my_dict = {"A":1, "B":2} #etc
print(my_dict[type])
复制代码
另外咱们在使用给对象的属性赋值的时候
class A():
def __init__(self,dicts):
self.name=dicts["name"]
self.age=dicts["age"]
self.sex=dicts["sex"]
self.hobby=dicts["hobby"]
if __name__ == '__main__':
dicts={"name":"lisa","age":23,"sex":"women","hobby":"hardstyle"}
a=A(dicts)
复制代码
咱们看到咱们须要换取传入的字典的各个键值,并建立键值同名一个属性,这里咱们只有4个还好,想象一下若是咱们传入的字典有100个键。。。如何仍是这样一个一个赋值不敢想不敢想,人家都写完代码了,你还在赋值有木有。。
其实一开始的那段代码已经给出了答案,若是不会也不要紧,
下面咱们就来点pythonic的python。来解决这个问题。
上面代码简化为:
class A():
def __init__(self,dicts):
self.__dict__.update(dicts)
print(self.__dict__)
if __name__ == '__main__':
dicts={"name":"lisa","age":23,"sex":"women","hobby":"hardstyle"}
a=A(dicts)
复制代码
咱们观察下面的代码
ls = []
for x in range(5):
ls.append(lambda: x**2)
print(ls[0]())
print(ls[1]())
print(ls[2]())
复制代码
咱们觉得它会输出[0],[1],[4].但实际状况是。。。。。
16
16
16
复制代码
这是什么鬼?
其实这和python的惰性求值有关。惰性求值,也就是延迟求值,表达式不会在它被绑定到变量以后就当即求值,而是等用到时再求值。x实际不在lambda的做用域中。只有当lambda被调用时,x的值才会被传给它。也就是最后的一次循环中x为4,后面的ls[1],ls[1],ls[2],ls[3]实际都是16。同时这是面试常考的一个点,但愿你们牢记。
这个问题考察了闭包。
执行文件的路径和当前的路径这是两个概念
获取文件的当前路径时能够的使用
import os
os.getcwd()
复制代码
可是在须要执行的文件的获取其执行路径的时候就最好不要用这个了。
通常使用下面这种方式,动态的获取路径
import sys
sys.path[0]
复制代码
eval("02")
复制代码
会发生错误:
Traceback (most recent call last):
File "/demo/1.py", line 1, in <module>
eval("02")
File "<string>", line 1
02
^
SyntaxError: invalid token
复制代码
python2的时候是这样,觉得python3 True=1因此结果实际是同样的。
因为Python2中,True/False不是关键字,所以咱们能够对其进行任意的赋值,这就致使程序在每次循环时都须要对True/False的值进行检查;而对于1,则被程序进行了优化,然后不会再进行检查。
Python3中,因为True/False已是关键字了,不容许进行从新赋值,所以,其执行结果与while 1再也不有区别
对于长的字符串咱们通常使用"""多文本"""的形式,可是换行的时候容易致使哪里出错,此时能够考虑在外面加个小括号,像这样
("""多文本""")
复制代码
做者实际上提供了个自动识别网页编码的代码,在获取res(请求的对象),获取源码以前使用
下面的代码便可获取正确的网站编码。
res.encoding=res.apparent_encoding
复制代码
更多工具使用以及python技巧,请关注公众号:python学习开发。
若是您喜欢个人文章不防动动小手转发一波,谢谢。点击阅读原文进入个人博客园,看代码更方便。因为人数超过100因此须要添加我微信:italocxa,而后拉您入群。