我是 Python 新手,我发现在制作课程时我一直需要编写
@property
def example(self):
return self._example
@example.setter
def example(self, example):
if #some conditions here:
self._example = example
不幸的是,这似乎不起作用。
我正在开发一个项目,其中有十几个这样的项目,因此我尝试创建一个函数,该函数将采用属性名称和一些条件,并为其创建 getter、setter 和 deleter。
class Util:
@classmethod
def custom_property(cls, prop, conds=None, deletable=False):
def getter(self):
return getattr(self, f'_{prop}')
def setter(self, value):
if conds is None or conds(value):
setattr(self, f'_{prop}', value)
else:
raise ValueError(f'Invalid value for {prop}')
def deleter(self):
if deletable:
del self._value
else:
print("This attribute can't be deleted.")
# setattr(target, prop, property(getter, setter, deleter))
return [getter, setter, deleter]
这是我尝试使用它的一个例子:
from utils import Util
def name_conds(name):
if not isinstance(name, str):
raise TypeError("City name must be a string")
if not name.strip():
raise ValueError("City name cannot be blank")
if not 2 <= len(name) <= 25:
raise ValueError("City name length must be between 2 and 25 characters")
return True
class City:
def __init__(self, name):
self._name = name
[name_getter, name_setter, name_deleter] = Util.custom_property("name", name_conds)
name = property(name_getter, name_setter, name_deleter)
不幸的是,这并不完全有效。如果我创建一个名为“asdf”的城市并尝试将其更改为“a”,我会得到正确的错误,即长度错误,但是如果我实例化一个名为“a”的新城市,我可以没有问题。人们肯定有办法像我一样绕过写出属性吗?另外,正如 Util 中的注释行所示,我希望能够通过在任何需要属性的类中调用 Util.custom_property 来以更快的方式使用该方法,但这将属性添加到了 Util 中(当然,因为它是将其添加到 cls)。似乎没有办法将 City 类作为 City 内部的参数,但是在 city 外部调用 custom_property 可能意味着 city 中的函数无法正确引用名称。
问题不在于您的财产,而在于您没有使用
City.__init__
中的财产。 _name
实际上是属性本身的私有实现细节(尽管该值存储在 City
的实例上),因此 City
方法也不应该直接使用它。
在回答问题时,我会指出
custom_property
不一定是类方法(或任何类的方法);它可以是一个普通的函数。此外,它还可以返回一个 property
实例本身,您可以将其直接分配给 City
的属性。最后,您可以通过定义一个在 setter
为 conds
时无条件设置值来优化 None
,并且如果 deletable
为 False
则可以省略删除器。
def custom_property(cls, prop, conds=None, deletable=False):
def getter(self):
return getattr(self, f'_{prop}')
if conds is None:
def setter(self, value):
setattr(self, f'_{prop}', value)
else:
def setter(self, value):
if conds(value):
setattr(self, f'_{prop}', value)
else:
raise ValueError(f'Invalid value for {prop}')
if deletable:
def deleter(self):
del self._value
else:
deleter = None
return property(getter, setter, deleter)
然后
from utils import custom_property
def name_conds(name):
if not isinstance(name, str):
raise TypeError("City name must be a string")
if not name.strip():
raise ValueError("City name cannot be blank")
if not 2 <= len(name) <= 25:
raise ValueError("City name length must be between 2 and 25 characters")
return True
class City:
def __init__(self, name):
self.name = name # Use the property, not _name
name = custom_property("name", name_conds)