0

I am looking for a way in python to build classes in python that:

  • setter check the type of the value before assignment
  • impossible to add new class attribute

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

asked Aug 4, 2017 at 21:31

1 Answer 1

2

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.

answered Aug 5, 2017 at 22:48
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.