Immutable attribute in python class and type check
I am looking for a way in python to build classes in python that:
for the time being I found those two decorators:
def getter_setter_gen(name, type_): def getter(self): return getattr(self, "__" + name) def setter(self, value): print "setter", value if not isinstance(value, type_): raise TypeError("%s attribute must be set to an instance of %s" % (name, type_)) setattr(self, "__" + name, value) return property(getter, setter) def auto_attr_check(cls): new_dct = {} print "auto_attr_check", cls.__dict__.items() for key, value in cls.__dict__.items(): if isinstance(value, type): value = getter_setter_gen(key, value) new_dct[key] = value # Creates a new class, using the modified dictionary as the class dict: n = type(cls)(cls.__name__, cls.__bases__, new_dct) return n
and
def froze_it(cls): def frozensetattr(self, key, value): print key key = ''+key print(dir(self)) print key if not hasattr(self, key): raise TypeError("Class {} is frozen. Cannot set {} = {}" .format(cls.__name__, key, value)) else: object.__setattr__(self, key, value) cls.__setattr__ = frozensetattr return cls
but I have a lot of trouble to join those two approach. Can you help me? Do you have ideas? Thanks a lot
The issue you're encountering is that your property
is using setattr
to set the value of your attributes, but that you've overridden __setattr__
in such a way that it can't ever succeed. The hasattr
check will fail for both the main property name, and for the underscore-prefixed name of the actual attribute that underlies the property (if the setter code could get that far).
I suggest two complementary fixes. First, change the hasattr
check to be a little more careful. If it fails, it should also check the class dict for a property object:
def frozensetattr(self, key, value):
if not hasattr(self, key) and type(cls.__dict__.get(key)) is not property:
raise TypeError("Class {} is frozen. Cannot set {} = {}"
.format(cls.__name__, key, value))
else:
object.__setattr__(self, key, value)
The second fix is to the setter
function, which should bypass the __setattr__
method for the underlying attribute:
def setter(self, value):
print "setter", value
if not isinstance(value, type_):
raise TypeError("%s attribute must be set to an instance of %s" % (name, type_))
object.__setattr__(self, "__" + name, value)
A final note: The double-underscore prefix on the attribute names created by your property
is not going to invoke name mangling, which I suspect it what you intend. Name mangling only happens at compile time. When a method contains an name like __bar
, the name gets transformed by the compiler to _NameOfTheClass__bar
(where NameOfTheClass
is the name of the class the method is defined in).
At runtime, the code behaves exactly as if the mangled name was written directly in the source. This means that __setattr__
and friends don't treat mangled names (or double-underscore prefixed names that would have been mangled by the compiler if they were written as regular variable names instead of strings) in any kind of special way. So there's no easy way to do name mangling on dynamically created variables.
If you just want your names to be informally marked as private (that is, they're not part of the public API), you should probably use a single leading underscore.
链接地址: http://www.djcxy.com/p/56432.html上一篇: PyAudio通过网络崩溃
下一篇: python类中的不可变属性和类型检查