在Python中以以下方式定义静态变量有什么问题吗?
如果您有一个不变的值,那么仅使用@property定义它并按如下方式返回值是否有任何错误:在Python中以以下方式定义静态变量有什么问题吗?,python,Python,如果您有一个不变的值,那么仅使用@property定义它并按如下方式返回值是否有任何错误: class Circle: def __init__(self, radius): self.radius = radius @property def pi(self): return 3.14 def area(self): return self.pi * self.radius 既然PI不应该改变,而且值是静态的,那么用@p
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def pi(self):
return 3.14
def area(self):
return self.pi * self.radius
既然PI不应该改变,而且值是静态的,那么用@property定义它是否有任何错误,如上图所示
我通常看到的是:
class Circle:
def __init__(self, radius):
self.radius = radius
self.pi = 3.14
def area(self):
return self.pi * self.radius
我认识的Python程序员通常避免使用访问器函数,除非他们实际上在执行计算。在这种情况下,最好将变量设置为类的成员:
类圆:
pi=3.14
定义初始(自身,半径):
自半径=半径
# ...
使用属性的问题是:
>>> d = Circle()
>>> d.pi
3.14
>>> d.pi = 3
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
d.pi = 3
AttributeError: can't set attribute
>>> Circle.pi = 3
>>> d.pi
3
>d=Circle()
>>>d.pi
3.14
>>>d.pi=3
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
d、 pi=3
AttributeError:无法设置属性
>>>圆1.pi=3
>>>d.pi
3.
您可以使用元类解决此问题:
class NoSet(type):
def __setattr__(self, name, value):
if name == 'pi':
raise Exception("Can't assign")
else:
super(NoSet, self).__setattr__(name, value)
class Circle(object):
__metaclass__ = NoSet
@property
def pi(self):
return 3.14
>>> d = Circle()
>>> d.pi
3.14
>>> d.pi = 3
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
d.pi = 3
AttributeError: can't set attribute
>>> Circle.pi = 3
Traceback (most recent call last):
File "<pyshell#52>", line 1, in <module>
Circle.pi = 3
File "<pyshell#43>", line 4, in __setattr__
raise Exception("Can't assign")
Exception: Can't assign
class-NoSet(类型):
定义设置属性(自身、名称、值):
如果名称='pi':
引发异常(“无法分配”)
其他:
超级(NoSet,self)。\uuuu setattr\uuuu(名称,值)
类圆(对象):
__元类=NoSet
@财产
def pi(自身):
返回3.14
>>>d=圆()
>>>d.pi
3.14
>>>d.pi=3
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
d、 pi=3
AttributeError:无法设置属性
>>>圆1.pi=3
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
圆1.pi=3
文件“”,第4行,在\uuuu setattr中__
引发异常(“无法分配”)
异常:无法分配
要在Python3中使用,请将类定义更改为类圆(object,metaclass=NoSet):
免责声明:我刚才刚试过这个,它似乎有效。我不能做出任何承诺,因为我没有太多的元类经验。我个人不会这样做,如果只是因为可能有合理的理由让某人更改该值,例如,如果他们需要更高的精度。如果希望确保该值不可变,可以定义拒绝设置的属性
class Circle:
_pi = 3.14
def __init__(self, radius):
self.radius = radius
@property
def pi(self):
return _pi
@pi.setter
def pi(self, value):
pass
...
pi是不可变的
c = Circle(1)
c.pi = 5 # The intent is to make it change
print c.pi # Output: 3.14, it still keeps origin.
的确将其标记为属性的唯一优点是,除非定义了setter,否则很难修改它。关于做计算的访问器函数-情况并非总是如此。。。如果这是一个昂贵的计算,那么它通常应该是一个函数来表示这一点。我认为目的是使它不可变(“静态”),因为您不能重新分配给
@property
方法。这将确保mycircle.pi
始终返回3.14
。可以在类级别创建@属性
,但它有点毛茸茸的。让它成为一个普通的类变量并相信用户不会修改它可能是最简单的。@TigerhawkT3好吧,你可以重新分配给@property,但这是你自己的方式,所以你自己决定吧。。。如果一个人真的对它不安全,或者担心意外赋值,那么使用\u pi
可能是一种方法,目的是使它不可变。@Samuel好的-你知道-如果有人足够努力-Python中没有任何属性是不可变的?所以,也许你最好的办法就是使用名称扭曲惯例来表示“你真的不应该改变这一点,但如果你这么做了……这是你的问题,不是我的问题”嗯。。。面积!=self.pi*self.radius。。。面积=self.pi*直径