鱼C论坛

 找回密码
 立即注册
查看: 2642|回复: 12

[已解决]函数调用为什么会改变全局变量

[复制链接]
发表于 2017-12-8 13:12:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. # 题目:特别的生日
  2. # 我们知道任何一个日期都可以用8个数字写成“yyyymmdd”这种形式,例如“20010101”表示2001年1月1日,小明发觉自己的生日非常特别,
  3. # 因为当自己的生日写成“yyyymmdd”的形式后,发觉这8个数字各不相同,而且从自己的生日以后,一直到今天就再也没有出现这样的日期了。请问小明的生日是哪年的哪天?请用程序解答。

  4. def check(day):
  5.     num = []
  6.     for i in range(4):
  7.         num.append(day[0] % 10)
  8.         day[0] //= 10
  9.     for i in range(2):
  10.         num.append(day[1] % 10)
  11.         day[1] //= 10
  12.     for i in range(2):
  13.         num.append(day[2] % 10)
  14.         day[2] //= 10
  15.     num.sort()
  16.     if num[0] != num[1] != num[2] != num[3] != num[4] != num[5] != num[6] != num[7]:
  17.         return True
  18.     else:
  19.         return False
  20. def yestoday(today):
  21.     if today[2] != 1:
  22.         today[2] -= 1
  23.     elif (today[1] in [2, 4, 6, 8, 9, 11]) == True:
  24.         today[2] = 31
  25.         today[1] -= 1
  26.     elif (today[1] in [5, 7, 10, 12]) == True:
  27.         today[2] = 30
  28.         today[1] -= 1
  29.     elif today[1] == 1:
  30.         today[2] = 31
  31.         today[1] = 12
  32.         today[0] -= 1
  33.     else:
  34.         if (((today[0] % 400) ==0) or (((today[0] % 100) != 0) and ((today[0] % 4) == 0))) == True:
  35.             today[2] = 29
  36.         else:
  37.             today[2] = 28
  38.         today[1] = 2
  39.     return today

  40. day = [2017, 12, 7]
  41. birthday = day[:]
  42. while True:
  43.     result = check(birthday)
  44.     if result == True:
  45.         break
  46.     else:
  47.         day = yestoday(day)
  48.         birthday = day[:]
  49. print('小明的生日是%d年%d月%d日' % (day[0], day[1], day[2]))
复制代码


在这个题目中,我调用自定义的check函数判断该日期是否符合要求,如果函数的输入值为变量day,但是函数运行结束后,为什么day这个变量就变成了[0, 0, 0]?为了解决这个问题我多加了一个变量birthday,保存day的数据。。。
最佳答案
2017-12-8 14:29:25
这不是全局变量与局部变量的问题,你没有搞清楚python中函数参数传递的方式。

首先在python中,一切变量都是对某个“对象”的“引用”,你在赋值、传递参数时,只不过是给一个“对象”建立了一个新的“引用”
当这个对象是数字常量、字符串、元组这类不可变对象的时候,你重新赋值就是创建了新的对象的引用
而当对象是列表、字典这类可变对象的时候,你做出的任何修改性赋值都是在原对象上进行修改,如果有多个变量是这个对象的“引用”,你就会发现这些变量都被“改变了”,因为事实上你只是改变了它们所引用的对象

具体可以去搜一搜比如python函数参数引用传递,浅拷贝与深拷贝等内容
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-12-8 13:16:50 | 显示全部楼层
第15行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-12-8 13:18:12 | 显示全部楼层

函数里面操作的对象都是局部变量啊,我没有对全局变量进行修改
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-8 13:25:12 | 显示全部楼层
Bill888 发表于 2017-12-8 13:18
函数里面操作的对象都是局部变量啊,我没有对全局变量进行修改

9,12,15行都是对传进来的列表进行操作,直接改变了里面的值
你哪里定义了局部变量?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-8 13:27:25 | 显示全部楼层
第50行不是重新将Day赋值给了birthday
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-12-8 13:38:49 | 显示全部楼层
BngThea 发表于 2017-12-8 13:25
9,12,15行都是对传进来的列表进行操作,直接改变了里面的值
你哪里定义了局部变量?

在第5行中,我不是把day定义为局部变量了吗?我重新看了一下小甲鱼老师《零基础学习Python》第19讲视频,按视频上面说的,day应该是局部变量
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-12-8 13:44:34 | 显示全部楼层
colinshi 发表于 2017-12-8 13:27
第50行不是重新将Day赋值给了birthday

我引入birthday这个变量就是为了解决如果将全局变量day直接代入函数check(day)中运行,全局变量day的值会变成[0, 0, 0]这个问题的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-8 14:01:14 | 显示全部楼层
Bill888 发表于 2017-12-8 13:38
在第5行中,我不是把day定义为局部变量了吗?我重新看了一下小甲鱼老师《零基础学习Python》第19讲视频, ...

你将day作为实参传递进去的时候,函数内部是可以修改实参
只有在函数内部定义的参数才是这个函数的局部变量
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-12-8 14:17:07 | 显示全部楼层
BngThea 发表于 2017-12-8 14:01
你将day作为实参传递进去的时候,函数内部是可以修改实参
只有在函数内部定义的参数才是这个函数的局部 ...

小甲鱼老师在《零基础学习Python》课程中定义了下面这个函数:
  1. def discounts(price, rate):
  2.     final_price = price * rate
  3.     return final_price
复制代码

然后说这里面的price, rate 和 final_price都是discounts函数的局部变量。如果有局部变量和全局变量变量名一样,Python会生成一个和全局变量名一样的局部变量,运算不会改变全局变量的值。
小甲鱼老师这个地方是不是讲错了?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-8 14:29:25 | 显示全部楼层    本楼为最佳答案   
这不是全局变量与局部变量的问题,你没有搞清楚python中函数参数传递的方式。

首先在python中,一切变量都是对某个“对象”的“引用”,你在赋值、传递参数时,只不过是给一个“对象”建立了一个新的“引用”
当这个对象是数字常量、字符串、元组这类不可变对象的时候,你重新赋值就是创建了新的对象的引用
而当对象是列表、字典这类可变对象的时候,你做出的任何修改性赋值都是在原对象上进行修改,如果有多个变量是这个对象的“引用”,你就会发现这些变量都被“改变了”,因为事实上你只是改变了它们所引用的对象

具体可以去搜一搜比如python函数参数引用传递,浅拷贝与深拷贝等内容
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-12-8 14:30:46 | 显示全部楼层
Bill888 发表于 2017-12-8 14:17
小甲鱼老师在《零基础学习Python》课程中定义了下面这个函数:

然后说这里面的price, rate 和 final_p ...
  1. def discounts(price, rate):
  2.     final_price = price * rate
  3.     price = 80
  4.     rate = 0.2
  5.     print('新的价格是:', price)
  6.     print('新的折扣是:', rate)
  7.     return final_price

  8. old_price = float(input('请输入原价:'))
  9. rate = float(input('请输入折扣率:'))
  10. new_price = discounts(old_price, rate)
  11. print('打折后价格是', new_price)
  12. print('旧的价格是:', old_price)
  13. print('旧的折扣是:', rate)
复制代码

这个程序的输出结果是:
请输入原价:100
请输入折扣率:0.8
新的价格是: 80
新的折扣是: 0.2
打折后价格是 80.0
旧的价格是: 100.0
旧的折扣是: 0.8
在这个程序中,我在函数discounts中修改price和rate的值,也没有改变输入的实参old_price和全局变量rate的值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-8 14:46:32 | 显示全部楼层
DarkmasterSugar 发表于 2017-12-8 14:29
这不是全局变量与局部变量的问题,你没有搞清楚python中函数参数传递的方式。

首先在python中,一切变量 ...

不对啊,切片不是应用,是复制。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-8 22:53:13 | 显示全部楼层
colinshi 发表于 2017-12-8 14:46
不对啊,切片不是应用,是复制。

我不知道你在误会些什么。

首先,我完全没有说过类似切片是“引用”这种不着边际的话。

再者,就切片而言,切片是对原始列表的一种浅拷贝,事实上已经生成了一个新对象,至于有没有引用要看你是不是把切片后的新对象赋值给了某个变量或者传递给了某个函数参数,这和我之前的回答完全没有冲突
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-27 14:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表