鱼C论坛

 找回密码
 立即注册
查看: 4231|回复: 11

[已解决]关于 __init__ 的参数的默认值

[复制链接]
发表于 2021-1-29 16:31:14 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 gux 于 2021-1-29 16:34 编辑

问题源于 零基础入门学习 Python 038节编程题 1。我试着定义了一个平面上的点的类 Point:
class Point:
    def __init__(self, cor = [0, 0]):
        self.cor = cor # 平面上一点的坐标

编辑器建议我把代码改为
class Point:
    def __init__(self, cor = None):
        if cor is None:
            cor = [0, 0]
        self.cor = cor

这样改的好处是什么?
最佳答案
2021-1-29 16:31:15

因为你第一个代码 默认参数的值设置为一个列表,因为列表是可变的,会导致你列表中元素可能发生改变

举个例子,下面这个代码执行同个函数就会导致原本是默认的参数变成变化的参数:
def test(list1=[], number=100):
    list1.append(number)
    print(list1)
    
test()
test()
test()

输出结果,每次调用同个函数,默认参数的结果都不同:
[100]
[100, 100]
[100, 100, 100]


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-1-29 16:31:15 | 显示全部楼层    本楼为最佳答案   

因为你第一个代码 默认参数的值设置为一个列表,因为列表是可变的,会导致你列表中元素可能发生改变

举个例子,下面这个代码执行同个函数就会导致原本是默认的参数变成变化的参数:
def test(list1=[], number=100):
    list1.append(number)
    print(list1)
    
test()
test()
test()

输出结果,每次调用同个函数,默认参数的结果都不同:
[100]
[100, 100]
[100, 100, 100]


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-1-29 18:27:38 | 显示全部楼层
你的编辑器真高级啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-1-29 21:50:03 | 显示全部楼层
本帖最后由 Stubborn 于 2021-1-29 21:51 编辑
# -*- coding: utf-8 -*-
# !/usr/bin/python3
"""
@ version: ??
@ author: Alex
"""

def function(val, val_type=None):
    """
     如果默认值是 可变类型容器,例如 list,dict,set
        那么应该把默认值设置为None,其代码这样写。
    """

    # if not val_type: 应该使用is None , 避免其他的参数,如 0、空集合、空列表被当做False误判

    if val_type is None:
        val_type = []

_no_value = object()
def function_one(val, val_type=_no_value):
    """
    如果不打算提供一个默认值
        只想检测可选参数是否被赋予了特定的值,其代码这样写。
    """
    if val_type is _no_value: # Note that _no_value is a global variable
        print("No val_type value supplied")

对默认参数的赋值,只在函数定义的时候绑定一次,例如上面 function_one 的默认参数,在定义的时候 val_type 已经指向了 object 对象,对 _no_value 的值修改,影响不到 val_type ,只会影响 if 判断。所以给参数的默认是应该总是:不可变对象、比如True,False,字符串,数字。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-1-30 11:27:14 | 显示全部楼层
什么编辑器,pycharm?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-1-30 17:00:04 | 显示全部楼层
这样改的好处就是不会在初始化时给赋予一个无意义的值
如果凭这个类的意义的话其实 cor 只能为一个具有两个值的序列,但是编辑器并不知道,所以默认给了 None
把判断 cor 是否合法放在内部判断就可以避免许多不应有的 bug
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-1 08:53:57 | 显示全部楼层
可能这样更好一点
def __init__(x,y):
        self.x = x,
        self.y = y
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-1 20:10:24 From FishC Mobile | 显示全部楼层
Alwyn_Yin 发表于 2021-2-1 08:53
可能这样更好一点
def __init__(x,y):
        self.x = x,

不太符合坐标系内任意点的定义吧
如果你这样只是描述了一个点的 x 轴和 y 轴的位置,并不完整
写成一个含有 2 个元素的序列似乎更好一点
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-2-4 00:19:41 | 显示全部楼层
Cool_Breeze 发表于 2021-1-30 11:27
什么编辑器,pycharm?

是的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2021-2-4 00:21:43 | 显示全部楼层
Stubborn 发表于 2021-1-29 21:50
对默认参数的赋值,只在函数定义的时候绑定一次,例如上面 function_one 的默认参数,在定义的时候 val ...

序列 [0, 0]是一个可变的对象吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-4 14:55:31 | 显示全部楼层
gux 发表于 2021-2-4 00:21
序列 [0, 0]是一个可变的对象吗?

列表属于可变对象,它是一个容器类,你往里面塞值,但是容器本身不会改变
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-2-7 18:32:44 | 显示全部楼层
就拿你这个例子来说,你测试一下下面的代码就明白会出什么问题了。
class Point:
    def __init__(self, cor=[0, 0]):
        self.cor = cor  # 平面上一点的坐标


p1 = Point()
p1.cor.append(1)

p2 = Point()
print(p2.cor)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-1-16 13:56

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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