Python - 如果在 class 中使用了未声明的变量,则强制出错
Python - Force an error if an undeclared variable is used inside a class
考虑以下 Python 代码:
class a_class:
defined_var = 1
def a_function(self):
self.defined_var = 2
self.undefined_var = 3
可以为我在 class 开始时未声明的变量赋值(然后隐式声明它)(就像我为
undefined_var
在前面的例子中)给我带来了几个问题,因为对于巨大的 classes 我忘记了我定义的和我没有定义的。
我知道这个问题听起来很傻。我已经使用 C/C++/Java 开发了很长一段时间,其中 class 中的变量定义是强制性的...
有没有办法避免这种情况?我的意思是,我想要像 C/C++/Java 这样的行为,如果我使用未定义的变量,我会收到错误消息。
您可以覆盖 object.__setattr__
:
class a_class:
defined_var = 1
def a_function(self):
self.defined_var = 2
self.undefined_var = 3
def __setattr__(self, key, value):
if hasattr(self, key):
object.__setattr__(self, key, value)
else:
raise AttributeError(f"\"{key}\" is not defined in \"{self.__class__.__name__}\"")
a = a_class()
print(a.defined_var)
a.a_function() # <-- throws an error
P.S. defined_var
是所有实例共享的 class 变量。这意味着所有更改都会影响 class 的所有实例(也许这不是您所期望的)。更多信息 here.
默认情况下,python 个实例有 __dict__
- a dictionary that stores all of the object's attributes. This is what allows them to store arbitrary attributes. You can suppress the creation of the __dict__
by defining __slots__
。这是一个 class 级变量,列出了 class 的所有属性实例的名称。如果 class 有 __slots__
,尝试分配给未定义的属性将抛出异常。
示例:
class MyClass:
__slots__ = ['defined_var']
def a_function(self):
self.defined_var = 2
obj = MyClass()
obj.a_function()
obj.undefined_var = 3 # throws AttributeError
只需在此处添加一些注释:
Python 的创建者 Guido van Rossum 表示,他实际上创建了 slots 以实现更快的属性访问。
from book fluent python,__slots__
用于更快的属性访问和减少内存使用,而不是阻止用户添加更多属性。
检查此代码:
class MyClass:
__slots__ = ['defined_var', '__dict__']
obj = MyClass()
obj.undefined_var = 3 # works fine
使用__slots__
时的问题,如果你创建这个class的子class,你也需要在其中重复__slot__
属性。
class MyClass:
__slots__ = ['defined_var']
class MySubClass(MyClass):
# you need to redefine the __slots__ here too
pass
obj = MyClass()
sub_obj = MySubClass()
sub_obj.undefined_var = 3 # works fine not excepting this
obj.undefined_var = 3 # throw exception
因此,如果您真的需要这个,请按照@Olvin Roght 的建议重写 setattr
方法。
class MyClass:
x = None
def __setattr__(self, key, value):
if hasattr(self, key):
object.__setattr__(self, key, value)
else:
raise AttributeError(f"\"{key}\" is not defined in \"{self.__class__.__name__}\"")
class MySubClass(MyClass):
pass
obj = MyClass()
sub_obj = MySubClass()
sub_obj.x = 3 # works fine
obj.x = 3 # works fine
sub_obj.undefined_var = 3 # error
obj.undefined_var = 3 # error
如果有一天你想对你的对象进行猴子修补:
obj = MyClass()
obj.__dict__['z'] = 4
print(obj.z) # print 4, we added a new attribute
所以不要担心阻止客户端添加新属性,这是一个坏习惯。你会阻止你自己控制你的对象并改变它的行为,消除 python 给你的灵活性,你为什么要那样。
考虑以下 Python 代码:
class a_class:
defined_var = 1
def a_function(self):
self.defined_var = 2
self.undefined_var = 3
可以为我在 class 开始时未声明的变量赋值(然后隐式声明它)(就像我为
undefined_var
在前面的例子中)给我带来了几个问题,因为对于巨大的 classes 我忘记了我定义的和我没有定义的。
我知道这个问题听起来很傻。我已经使用 C/C++/Java 开发了很长一段时间,其中 class 中的变量定义是强制性的...
有没有办法避免这种情况?我的意思是,我想要像 C/C++/Java 这样的行为,如果我使用未定义的变量,我会收到错误消息。
您可以覆盖 object.__setattr__
:
class a_class:
defined_var = 1
def a_function(self):
self.defined_var = 2
self.undefined_var = 3
def __setattr__(self, key, value):
if hasattr(self, key):
object.__setattr__(self, key, value)
else:
raise AttributeError(f"\"{key}\" is not defined in \"{self.__class__.__name__}\"")
a = a_class()
print(a.defined_var)
a.a_function() # <-- throws an error
P.S. defined_var
是所有实例共享的 class 变量。这意味着所有更改都会影响 class 的所有实例(也许这不是您所期望的)。更多信息 here.
默认情况下,python 个实例有 __dict__
- a dictionary that stores all of the object's attributes. This is what allows them to store arbitrary attributes. You can suppress the creation of the __dict__
by defining __slots__
。这是一个 class 级变量,列出了 class 的所有属性实例的名称。如果 class 有 __slots__
,尝试分配给未定义的属性将抛出异常。
示例:
class MyClass:
__slots__ = ['defined_var']
def a_function(self):
self.defined_var = 2
obj = MyClass()
obj.a_function()
obj.undefined_var = 3 # throws AttributeError
只需在此处添加一些注释:
Python 的创建者 Guido van Rossum 表示,他实际上创建了 slots 以实现更快的属性访问。
from book fluent python,__slots__
用于更快的属性访问和减少内存使用,而不是阻止用户添加更多属性。
检查此代码:
class MyClass:
__slots__ = ['defined_var', '__dict__']
obj = MyClass()
obj.undefined_var = 3 # works fine
使用__slots__
时的问题,如果你创建这个class的子class,你也需要在其中重复__slot__
属性。
class MyClass:
__slots__ = ['defined_var']
class MySubClass(MyClass):
# you need to redefine the __slots__ here too
pass
obj = MyClass()
sub_obj = MySubClass()
sub_obj.undefined_var = 3 # works fine not excepting this
obj.undefined_var = 3 # throw exception
因此,如果您真的需要这个,请按照@Olvin Roght 的建议重写 setattr
方法。
class MyClass:
x = None
def __setattr__(self, key, value):
if hasattr(self, key):
object.__setattr__(self, key, value)
else:
raise AttributeError(f"\"{key}\" is not defined in \"{self.__class__.__name__}\"")
class MySubClass(MyClass):
pass
obj = MyClass()
sub_obj = MySubClass()
sub_obj.x = 3 # works fine
obj.x = 3 # works fine
sub_obj.undefined_var = 3 # error
obj.undefined_var = 3 # error
如果有一天你想对你的对象进行猴子修补:
obj = MyClass()
obj.__dict__['z'] = 4
print(obj.z) # print 4, we added a new attribute
所以不要担心阻止客户端添加新属性,这是一个坏习惯。你会阻止你自己控制你的对象并改变它的行为,消除 python 给你的灵活性,你为什么要那样。