自从我开始开发一个想要发布的包以来,我一直在考虑私有类属性和方法(后续阅读中称为成员)。它背后的想法从来都不是不可能覆盖这些成员,而是对那些接触它们的人发出警告。我想到了一些可能有用的解决办法。第一个解决方案在我最喜欢的Python书籍之一《Fluent Python》中使用。
技术1的优点:
它不太可能被意外覆盖。
它很容易理解和实现。
它比实例属性的前双下划线更容易处理。
*在书中使用了哈希符号,但你也可以使用整数转换为字符串。在Python中,禁止使用class .1
class Technique1:
def __init__(self, name, value):
setattr(self, f'private#{name}', value)
setattr(self, f'1{name}', value)
技术1的缺点:
但是,使用这种技术不容易保护方法。这是可能的。
属性查找只能通过getattr实现
仍然没有对用户发出警告
我遇到的另一个解决方案是编写__setattr__。优点:
它很容易实现和理解
它与方法一起工作
查找不受影响
用户得到一个警告或错误
class Demonstration:
def __init__(self):
self.a = 1
def method(self):
return None
def __setattr__(self, name, value):
if not getattr(self, name, None):
super().__setattr__(name, value)
else:
raise ValueError(f'Already reserved name: {name}')
d = Demonstration()
#d.a = 2
d.method = None
缺点:
您仍然可以重写类
为了让变量不仅仅是常量,您需要映射允许的输入。
子类仍然可以覆盖方法
为了防止子类覆盖方法,你可以使用__init_subclass__:
class Demonstration:
__protected = ['method']
def method(self):
return None
def __init_subclass__(cls):
protected_methods = Demonstration.__protected
subclass_methods = dir(cls)
for i in protected_methods:
p = getattr(Demonstration,i)
j = getattr(cls, i)
if not p is j:
raise ValueError(f'Protected method "{i}" was touched')
可以看到,有很多方法可以保护类成员,但不能保证用户不会覆盖它们。这应该能给你们一些启发。最后,您还可以使用元类,但这可能会带来新的危险。这里使用的技术也非常简单,你应该看看文档,你可以找到这个技术的有用特性,并根据你的需要定制它们。