I need to get the name of a variable from within a function it call during assignment. For example if we take the code:
class CharField:
def __init__(self):
self.field_name = ???
class Person:
name = CharField() # this is a field
zodiac = CharField() # this is a field
How do i get the the field names (name
and zodiac
) from within the init method of CharField?
Please don't just comment that it is not possible since in one way or another the sqlalchemy library (and other python ORMs) all does it some how, we define models and fields with a dataclass just like above with Person
and somehow sqlalchemy use it to generate a SQL statement containing the name of the field, so there must be a way..
I tried looking into python call stack for the name of the variable and technically it is there in the form of a string containing the entire line of code filepath.. name = CharField()
. I could always extract it from this string but i have been told it is a messy way to do it that should not be used.
This can be done by making CharField
a descriptor so you can obtain the attribute name that an instance of the descriptor is assigned to with the __set_name__
method.
The descriptor should be defined with __get__
and __set__
methods to allow the value of attribute to be accessed and updated.
To prevent the name of the instance attribute from shadowing the name of the descriptor, you should name the instance attribute differently, typically by prefixing the descriptor name with an underscore:
class CharField:
def __set_name__(self, owner, name):
self.field_name = name
self.private_name = '_' + name
def __get__(self, obj, objtype=None):
value = getattr(obj, self.private_name)
print(f'Accessing field {self.field_name!r} giving {value!r}')
return value
def __set__(self, obj, value):
print(f'Updating field {self.field_name!r} to {value!r}')
setattr(obj, self.private_name, value)
so that:
class Person:
name = CharField()
zodiac = CharField()
person = Person()
person.name = 'Foo'
print(person.name)
would output:
Updating field 'name' to Foo
Accessing field 'name' giving Foo
Foo