首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

萌新python掉坑自救,一个小问题的解决的正确姿势

python作为一个简洁,灵活的编程语言,很多萌新开始连续跳坑,但是简单,灵活的同时,python也会有很多陷阱,很容易把自己套进去。

今天我给大家总结1工作中常见的坑,防止大家跳进去时,可以爬出来,当然很多题也成为了各大互联网公司的萌新笔试题,多了解一些,总是没坏处,资深大佬可以绕路,本位给萌新小白白。

直接上干活,我就不墨迹了,排名不分先后,想到哪里写哪里。

在python中定义函数的时候,我们可以给函数增加一个默认值,这个特性十分方便,但是当默认值可变的时候,也会出现一个大坑,进去了,可能就要折腾很久,比如下面的函数。

我们经常犯的错误就是,想当然的会以为,每次调用函数toutiao()的时候,如果没有可选参数传入,那么这个参数就会被指定为默认值,在上面的代码中你可能会觉得toutiao()一直会返回['woshikeng'],因为每次执行toutiao()的时候没有指定 参数keng的值,默认就使用默认值,可是事实可能要打脸了,

是不是很奇怪,为什么每次调用toutiao()函数的时候,keng都会把“woshikeng”这个默认值添加到已有的链表中,而不是新建一个空链表呢?

是因为,python可选参数的默认值的设置在Python中只会被执行一次,也就是定义该函数的时候。因此,只有当toutiao()函数被定义时,keng参数才会被初始化为默认值(也就是,一个空列表),但是之后每次toutiao()函数被调用时,都会继续使用keng参数原先初始化生成的那个列表,这是python特性,一不小心,很可能进去。

那么我们有什么好的解决方法呢?一个常见的解决办法是这样:

这样就可以避免发生上面的问题了

那么我就要解释一下,为什么这样做就行了的原因,首先我要讲下面几个问题:

1 、python变量的本质(与c对比):

大家看以上代码,如果这段代码是c语言代码,那么变量a的本质是这样的,编译器为a申请一个内存0x0001,内存里面存的是1,当运行到a=a+1时,计算出结果为2,那么a的地址不变,把2存到a的这个地址,这是c语言的做法。

python中怎么做呢,python中的一切都是类,所以整数也是类,那个1是个类,a这种变量是类似于c的指针的存在,即a存的是个地址,这个地址存储了指向了1所在类的地址空间,和c的指针差不多。

2、那么开始普及第二个知识:

用整数的实现说明下python可变对象和不可变对象。

python整数对象的实现,python解释器为了提高自己的效率,搞了一个整数池,分出了大整数和小整数,我记得是这个名字哈,小整数是编译器执行的时候就确定好了的,也就是小整数赋值那么地址不变,一直就是这个,大整数赋值就需要重新申请地址,为啥要这么干呢,主要是为了提高效率,要不然经常用到的小整数,频繁的申请内训、释放内存很浪费时间,所以就做了这个机制,而这个小整数的范围好像是-5~276 这个我不记得,但是我编译过python源码,这个范围可以改,是两个常量。

我觉得类似于redis缓存、数据库线程池等机制,解决频繁创建和销毁的开销,只是这个缓存比较傻呆萌,不过应该比较好用,因为这种大小整数池机制,当然除了整数还有字符串(字符串比较奇葩)等被称为了不可变对象,像空list这样的就是可变对象,简单的理解,不可变对象,内存地址永远不变,变量得自己变自己的地址,可变对象你能都动他地址里的值,变量自己不用改变自己的指向的地址。

知道以上两个知识,你就明白了python变量赋值的时候a=1时,这个1是不可变对象,所以当a=a+1时a的地址必须变成整数2的地址,因为1是小整数不可变对象是不能改变的,变量a只能自己变。

但是如果是链表list1=[], list.append("ss"),那么此时a变量就不用改自己的地址了,让list1自己变就行,因为list1是可变的,就是欺负你能变。

3、在说第三个知识点:

python世界里,一切都是对象,所以函数toutiao()这个函数也是个对象,大家知道对象是在编译器编译的时候就要确定的,而函数的默认值在pyton世界相当于类的属性,所以toutiao()的默认值keng在编译就被赋予了可变对象[]( []代表了了默认函数keng=[]中的[]),

那么现在回来看这个问题就很明白了:

编译阶段keng赋值了可变对象[],keng里面存的是[]的地址,在第一次调用的时候keng的地址不变,[]是老实人,让他自己变。所以[]变成了["woshikeng"],第二次调用的时候,还是["woshikeng"]变成了["woshikeng", "woshikeng"]就会出现了奇葩的大坑。

而小编的解决办法,让在编译阶段keng =None,这样调用的时候就判断会重新申请内存[],下次调用,又会重新申请内存[],所以解决这个问题了。

码字太不容易了,转载的老哥们手下留情,可以找小编约稿~

骚气公众号

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171220A0GJ4W00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券