class 个变量的设置器
Setters for class variables
我在名为 foo.py
:
的模块中有一个简单的 class
class Foo
foo = 1
我将其导入其他模块(bar.py
和 baz.py
)并在这些其他模块中更改 class 变量 foo
,例如:
# bar.py
from foo import Foo
print(Foo.foo) # should print 1.
Foo.foo = 2
和
# baz.py
from foo import Foo
print(Foo.foo) # should print 2.
Foo.foo = 3
然而,对 Foo.foo
的更改应在设置之前进行检查。因此,我目前在 Foo
:
中使用 setter 方法
# foo.py
@classmethod
def set_foo(cls, new_foo):
# do some checks on the supplied new_foo, then set foo.
cls.foo = new_foo
这是设置 class 变量的 pythonic 方法吗? 或者有更好的方法(类似于 @property a
和 @a.setter
实例变量的声明)?我希望 class 变量 foo
在这些其他模块中导入 Foo
时保持不变,我真的不想创建 Foo
的实例,因为它更像是一个 class 我猜的东西。
非常感谢 ;-)
如果您打算从 Foo
继承,请注意 classmethod
将修改 调用实例的 class 的属性。
class Base:
class_variable = 'base'
@classmethod
def set_cvar(cls, value):
cls.class_variable = value
class Derived(Base):
pass
Derived.set_cvar('derived')
print(Base.class_variable)
print(Derived.class_variable)
输出:
base
derived
这可能(可能会)是您想要的,也可能不是。另一种方法是使用 staticmethod
并明确命名您的 class。
不过,总的来说,我认为这是一个好方法。
我觉得'pythonic way',如果有,就用a.setter,使用_格式:
@property
def bar(self):
return self._bar
@bar.setter
def environment(self, bar):
# do some checks on the supplied bar, then set
self._bar = bar
这样 _bar 就是 'private',你可以在你的代码中 'bar' 设置它。
如果您不介意一点点魔法,这可以通过使用描述符协议相对理智地完成。
class FooDescriptor:
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj._foo
def __set__(self, obj, value):
if not isinstance(obj, type):
# disable instance name shadowing for sanity's sake
raise AttributeError("this attribute should be set on the class object")
obj._foo = value + "!!"
class FooMeta(type):
foo = FooDescriptor()
def __new__(cls, clsname, bases, namespace):
# pluck the "foo" attr out of the class namespace,
# and swap in our descriptor in its place
namespace["_foo"] = namespace.pop("foo", "(default foo val)")
namespace["foo"] = FooMeta.foo
return type.__new__(cls, clsname, bases, namespace)
在构建 class Foo
时,这将用数据描述符替换以正常声明方式定义的 foo
class 属性(以提供自定义 getter 和二传手)。我们将把原始 "unmanaged" 值存储在 Foo._foo
中。
演示:
>>> class Foo(metaclass=FooMeta):
... foo = "foo0"
...
>>> obj = Foo()
>>> obj.foo # accessible from instance, like a class attr
'foo0'
>>> Foo.foo # accessible from class
'foo0'
>>> Foo.foo = "foo1" # setattr has magic, this will add exclams
>>> obj.foo
'foo1!!'
>>> Foo.foo
'foo1!!'
>>> vars(obj) # still no instance attributes
{}
>>> type(Foo).foo # who does the trick?
<__main__.FooDescriptor at 0xcafef00d>
>>> obj.foo = "boom" # prevent name shadowing (optional!)
AttributeError: this attribute should be set on the class object
我在名为 foo.py
:
class Foo
foo = 1
我将其导入其他模块(bar.py
和 baz.py
)并在这些其他模块中更改 class 变量 foo
,例如:
# bar.py
from foo import Foo
print(Foo.foo) # should print 1.
Foo.foo = 2
和
# baz.py
from foo import Foo
print(Foo.foo) # should print 2.
Foo.foo = 3
然而,对 Foo.foo
的更改应在设置之前进行检查。因此,我目前在 Foo
:
# foo.py
@classmethod
def set_foo(cls, new_foo):
# do some checks on the supplied new_foo, then set foo.
cls.foo = new_foo
这是设置 class 变量的 pythonic 方法吗? 或者有更好的方法(类似于 @property a
和 @a.setter
实例变量的声明)?我希望 class 变量 foo
在这些其他模块中导入 Foo
时保持不变,我真的不想创建 Foo
的实例,因为它更像是一个 class 我猜的东西。
非常感谢 ;-)
如果您打算从 Foo
继承,请注意 classmethod
将修改 调用实例的 class 的属性。
class Base:
class_variable = 'base'
@classmethod
def set_cvar(cls, value):
cls.class_variable = value
class Derived(Base):
pass
Derived.set_cvar('derived')
print(Base.class_variable)
print(Derived.class_variable)
输出:
base
derived
这可能(可能会)是您想要的,也可能不是。另一种方法是使用 staticmethod
并明确命名您的 class。
不过,总的来说,我认为这是一个好方法。
我觉得'pythonic way',如果有,就用a.setter,使用_格式:
@property
def bar(self):
return self._bar
@bar.setter
def environment(self, bar):
# do some checks on the supplied bar, then set
self._bar = bar
这样 _bar 就是 'private',你可以在你的代码中 'bar' 设置它。
如果您不介意一点点魔法,这可以通过使用描述符协议相对理智地完成。
class FooDescriptor:
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj._foo
def __set__(self, obj, value):
if not isinstance(obj, type):
# disable instance name shadowing for sanity's sake
raise AttributeError("this attribute should be set on the class object")
obj._foo = value + "!!"
class FooMeta(type):
foo = FooDescriptor()
def __new__(cls, clsname, bases, namespace):
# pluck the "foo" attr out of the class namespace,
# and swap in our descriptor in its place
namespace["_foo"] = namespace.pop("foo", "(default foo val)")
namespace["foo"] = FooMeta.foo
return type.__new__(cls, clsname, bases, namespace)
在构建 class Foo
时,这将用数据描述符替换以正常声明方式定义的 foo
class 属性(以提供自定义 getter 和二传手)。我们将把原始 "unmanaged" 值存储在 Foo._foo
中。
演示:
>>> class Foo(metaclass=FooMeta):
... foo = "foo0"
...
>>> obj = Foo()
>>> obj.foo # accessible from instance, like a class attr
'foo0'
>>> Foo.foo # accessible from class
'foo0'
>>> Foo.foo = "foo1" # setattr has magic, this will add exclams
>>> obj.foo
'foo1!!'
>>> Foo.foo
'foo1!!'
>>> vars(obj) # still no instance attributes
{}
>>> type(Foo).foo # who does the trick?
<__main__.FooDescriptor at 0xcafef00d>
>>> obj.foo = "boom" # prevent name shadowing (optional!)
AttributeError: this attribute should be set on the class object