简体   繁体   English

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

[英]Implementing a property using the double asterisk (**)

Following http://www.programiz.com/python-programming/property , I'm familiar with the following method of implementing a property in Python: 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)

I'm now reading some code in which the double asterisk ( ** ) is used in defining the property. 我现在正在阅读一些代码,其中使用双星号( ** )来定义属性。 If I adapt it to my own example, it seems to be like this: 如果我将其调整为适合自己的示例,则它看起来像这样:

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())

However, if I try to run this code and instantiate a class through c = Celsius() , I get 但是,如果我尝试运行此代码并通过c = Celsius()实例化一个类,则会得到

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

I understand that fget and fset are keyword arguments of property , so I would expect what comes out of **temperature() to be something like fget=fget, fset=fset , but I am not sure what is going wrong here or how to dissect it further. 据我所知, fgetfset是关键字参数property ,所以我希望什么出来的**temperature()是像fget=fget, fset=fset ,但我不知道这到底是怎么还是走错了如何进一步剖析。 Any ideas? 有任何想法吗?

You should return the nested functions and then unpack them according from the function call: 您应该return嵌套函数,然后根据函数调用将其解压缩:

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

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

    temperature = property(*temperature())

If you insist on using ** , then you'll be returning a mapping/dictionary from your function which will then be unpacked as keyword arguments. 如果您坚持使用** ,那么您将从函数中返回映射/字典,然后将其解压缩为关键字参数。

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

temperature = property(**temperature())

You are getting that error because the temperature() call returns None , which you then attempt to unpack as if it were a dictionary, using ** . 之所以会出现此错误,是因为temperature()调用返回None ,然后您尝试使用**将其解包为字典。 So to get that code working you need to return an appropriate dictionary containing the setter & getter methods. 因此,要使该代码正常工作,您需要返回一个包含setter和getter方法的适当字典。

I prefer Moses' solution, but you could pass the methods with a dict instead of a tuple if you really want. 我更喜欢Moses的解决方案,但是如果您确实愿意, 可以使用dict而不是元组传递方法。 Eg, 例如,

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)

output 产量

Setting value
Getting value
20

Indeed I had missed the return statement in the function definition of temperature . 确实,我错过了temperature函数定义中的return语句。 The original code actually contains the line 原始代码实际上包含该行

return locals()

Adding this line makes the property work as intended. 添加此行使该属性按预期工作。

The temperature method you are defining does not have a return statement, so it implicitly returns None , this the ...,not NoneType in your error message. 您定义的temperature方法没有return语句,因此它隐式返回None ,这是错误消息中的...,not NoneType The method does have two sub-methods, but that does not cause it to return them in any form, I think you are missing a line such as ( untested ): 该方法确实有两个子方法,但是这不会导致它以任何形式返回它们,我认为您缺少诸如(untested)之类的行:

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

You could also use a list and a single * . 您还可以使用一个列表和一个*

That being said, it's a best practice to avoid * and ** magic, there's also a pylint rule to discourage it. 话虽如此,这是避免***魔术的最佳实践,也有防止这种情况的柔道规则

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM