使用双星号(**)实现属性

时间:2016-10-04 13:26:40

标签: python properties

关注http://www.programiz.com/python-programming/property,我熟悉以下在Python中实现属性的方法:

class Celsius(object):
    def __init__(self, temperature = 0):
        self._temperature = temperature

    def get_temperature(self):
        print("Getting value")
        return self._temperature

    def set_temperature(self, value):
        if value < -273:
            raise ValueError("Temperature below -273 is not possible")
        print("Setting value")
        self._temperature = value

    temperature = property(get_temperature, set_temperature)

我现在正在阅读一些代码,其中双星号(**)用于定义属性。如果我将它改编为我自己的例子,它似乎是这样的:

class Celsius(object):
    def __init__(self, temperature = 0):
        self._temperature = temperature

    def temperature():
        def fget(self):
            print("Getting value")
            return self._temperature
        def fset(self, value):
            if value < -273:
                raise ValueError("Temperature below -273 is not possible")
            print("Setting value")
            self._temperature = value

    temperature = property(**temperature())

但是,如果我尝试运行此代码并通过c = Celsius()实例化一个类,我会得到

TypeError: type object argument after ** must be a mapping, not NoneType

我理解fgetfsetproperty的关键字参数,所以我希望**temperature()的内容与fget=fget, fset=fset类似,但我不确定这里出了什么问题,或者如何进一步剖析它。有什么想法吗?

4 个答案:

答案 0 :(得分:2)

您应该return嵌套函数,然后根据函数调用解压缩它们:

class Celsius(object):
    def __init__(self, temperature = 0):
        self._temperature = temperature

    def temperature():
        ...
        return fget, fset

    temperature = property(*temperature())

如果你坚持使用**,那么你将从你的函数返回一个映射/字典,然后解压缩作为关键字参数。

def temperature():
    ...
    return {'fget': fget, 'fset': fset}

temperature = property(**temperature())

答案 1 :(得分:1)

您收到该错误是因为temperature()调用返回None,然后您尝试使用**解压缩,就好像它是字典一样。因此,要使代码正常工作,您需要返回包含setter和amp;的相应字典。 getter方法。

我更喜欢摩西的解决方案,但是如果你真的想要的话,可以传递dict而不是元组的方法。例如,

class Celsius(object):
    def __init__(self, temperature = 0):
        self._temperature = temperature

    def temperature():
        def fget(self):
            print("Getting value")
            return self._temperature
        def fset(self, value):
            if value < -273:
                raise ValueError("Temperature below -273 is not possible")
            print("Setting value")
            self._temperature = value
        return {'fget': fget, 'fset': fset}

    temperature = property(**temperature())

# Test
a = Celsius()
a.temperature = 20
print(a.temperature)

<强>输出

Setting value
Getting value
20

答案 2 :(得分:0)

确实我错过了return函数定义中的temperature语句。原始代码实际上包含行

return locals()

添加此行可使属性按预期工作。

答案 3 :(得分:0)

您定义的temperature方法没有return语句,因此它隐式返回None,这是您的错误消息中的...,not NoneType。该方法确实有两个子方法,但这并不会导致它以任何形式返回它们,我认为你缺少一条线,如(未经测试):

return { "fget": fget, "fset": fset }

您还可以使用列表和单个*

话虽这么说,避免***魔法是最佳做法,但也有pylint rule来阻止它。