Exercise 5.4 Need help with eliminating names from typedproperty
In the last challenge of this exercise, we are asked to eliminate the need for providing names to typedproperty. I can't get this to work with the closure template provided. Can I get some more hints or just the solution, as I have been banging my head against this problem for a couple of hours now? I realize that __set_name__ is called under the hood when assigning properties to the class, and this was pretty clear in the valiidate.py exercise. I'm unsure how this works when extending the class with these typedproperty methods. Thanks for the help.
I'm also curious to see how to bind set_name function with property object. Any hint or solution will be appreciated
how to bind set_name function with property object.
class MyClass: def init(self): self._name = ""
def get_name(self):
return self._name
def set_name(self, value):
self._name = value
name = property(get_name, set_name)
obj = MyClass() obj.name = "blah" print(obj.name) # Output: blah
Is discussing solutions ok in this thread?
Spoiler warning for my solution
Unsure if this is the intended solution or I've missed something which may cause a bug later on. I tried to override the __set_name__ method of the property. Unfortunately, it's read-only.
The next attempt consisted of subclassing from property:
class special_property(property):
def __set_name__(self, cls, name):
self.public_name = name
self.private_name = '_' + name
super().__set_name__(cls, name)
The instance, value now knows its own public and private names, and is accessed via:
def typedproperty(expected_type):
@special_property
def value(self):
return getattr(self, value.private_name)
@value.setter
def value(self, val):
if not isinstance(val, expected_type):
raise TypeError(f'Expected {expected_type}')
setattr(self, value.private_name, val)
return value
Thanks, jrmylow.
After commenting out this line "super().__set_name__(cls, name)" in "__set_name__" method of special_property class, your solution works well now. Otherwise, it will throw some error.
To answer an earlier question, I'm okay with solution discussion here. I never provided a solution to this (or any hints really). However, the only mechanism that Python provides to learn the name is __set_name__(). So, whatever the solution might be, it has to involve that in some way.
One thing that is a little unsettling in this exercise is the idea that you could dynamically create a property inside a function and return it back as an object like this. Python lets you create anything you want inside a function and return it back. This has some application later when the course gets into metaprogramming.
Hint: use set_name inside the typedproperty function so that it can access the name of the attribute that it's assigned to.
Spoiler alert
def typedproperty(expected_type):
def __set_name__(attr_name):
private_name = "_" + attr_name
@property
def value(self):
return getattr(self, private_name)
@value.setter
def value(self, value):
if not isinstance(value, expected_type):
raise TypeError(F"Expected {expected_type}")
setattr(self, private_name, value)
return value
This is my solution:
def typedproperty(expected_type):
private_name = None
class NamedProperty(property):
def __set_name__(self, cls, name):
nonlocal private_name
private_name = '_' + name
def _get(self):
return getattr(self, private_name)
def _set(self, val):
if not isinstance(val, expected_type):
raise TypeError(f"Expected {expected_type}")
setattr(self, private_name, val)
return NamedProperty(_get, _set)