[英]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. 据我所知,
fget
和fset
是关键字参数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.