Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
[Share] Just an idea to give seemly simple params some structured interface
-
Well, it's a quite night on the forum tonight, so I may as well share something. I think it's smart idea, but I have been proven wrong many times before :( What I am posting is not finished but its enough to see the intent.
The intent I have in mind is to provide some simple data structures /classes for parameters to lib functions such as dialogs. I know, the param list is simple enough, but in practice you end up writing a lot of code to support the params. And not in a structured way.
Look, I accept if I am wrong. But it seems to me that when you write a lib, if you could support it with a type of generic data/param interface class without much work it would be a big bonus.
Just an idea# coding: utf-8 import ui import dialogs _fld_attrs = { 'type': None, 'key' : None, 'value' : '', 'title' : None, 'tint_color': None, 'icon' : None, 'placeholder': '', 'autocorrection' : False, 'autocapitalization' : False, } class DialogFormField (object): def __init__(self, **kwargs): ''' DialogFormField Just start of an idea to create an easy way to give more comlicated params to functions/methods some form of structured params. i could be off on the wrong track. But while the params look easy enough to a lot of libs, in practice they make for a lot code. also dot notation not avalible etc... Again, is not finished... just exploring ''' # create the class attributes from a dict for attr in _fld_attrs: setattr(self, attr, _fld_attrs[attr]) ''' # fields as per definition of the # dialog.form_dialog() self.type = None self.key = None self.value = '' self.title = None self.tint_color = None self.icon = None self.placeholder = 'Enter your text...' self.autocorrection = False self.autocapitalization = False ''' # maybe this needs to be stronger. In my testing # it has been ok. but maybe some tricky stuff, # i dont know about. self.flds = [attr for attr in dir(self) if not attr.startswith('__') and not callable(getattr(self, attr))] for k in kwargs: if hasattr(self, k): setattr(self, k, kwargs[k]) # calling this because can not declare any more # attributes in this method. we want to get a # list of the field attrs. So can declare more # class attrs in the init2 method. self.init2() def init2(self): ''' just some test values to prove these attrs are not getting in the way ''' self.another_item = 'init2' self.xxx = 'init2' def get_dict(self): return {attr : getattr(self, attr) for attr in self.flds} if __name__ == '__main__': flds = [] fld = DialogFormField(title = 'test', type = 'text', tint_color = 'blue', placeholder = 'Enter your text...') fld.icon = 'typb:Anchor' fld.key = 'TextVal' flds.append(fld.get_dict()) x = DialogFormField() x.type = 'switch' x.title = 'My switch' x.value = 'True' x.key = 'SwitchVal' flds.append(x.get_dict()) d = dialogs.form_dialog(title = 'Test', fields = flds) print d
-
Ok, I see self.flds should be made up when the attributes are been set from the dict. This helps simply the class a lot.
-
Simplified code
# coding: utf-8 import ui import dialogs _fld_attrs = { 'type': None, 'key' : None, 'value' : '', 'title' : None, 'tint_color': None, 'icon' : None, 'placeholder': '', 'autocorrection' : False, 'autocapitalization' : False, } class DialogFormField (object): def __init__(self, **kwargs): ''' DialogFormField Just start of an idea to create an easy way to give more comlicated params to functions/methods some form of structured params. i could be off on the wrong track. But while the params look easy enough to a lot of libs, in practice they make for a lot code. also dot notation not avalible etc... Again, is not finished... just exploring ''' self.flds = [] # create the class attributes from a dict for attr in _fld_attrs: setattr(self, attr, _fld_attrs[attr]) self.flds.append(attr) # set the attrs for k in kwargs: if hasattr(self, k): setattr(self, k, kwargs[k]) def get_dict(self): return {attr : getattr(self, attr) for attr in self.flds} if __name__ == '__main__': flds = [] fld = DialogFormField(title = 'test', type = 'text', tint_color = 'blue', placeholder = 'Enter your text...') fld.icon = 'typb:Anchor' fld.key = 'TextVal' flds.append(fld.get_dict()) x = DialogFormField() x.type = 'switch' x.title = 'My switch' x.value = 'True' x.key = 'SwitchVal' flds.append(x.get_dict()) d = dialogs.form_dialog(title = 'Test', fields = flds) print d```
-
@Phuket2 Instead of manually converting
dict
s into attributes and vice-versa, consider using an actualdict
internally (self.style_dict
) and overwriting__getattr__
and__setattr__
. Anything listed underself.flds
would automatically be redirected toself.style_dict
, anything else stays a normal attribute.The
__*attr__
methods are a little tricky to customize though.__getattr__
is probably the easiest one, it only gets called when there is no "real" attribute with a certain name. However__setattr__
and__delattr__
are always called, no matter if the attribute is "real" or not. In cases where you don't want custom behavior, you need to manually redirect the method to the superclass:class DialogFormField(object): def __setattr__(self, name, value): super(DialogFormField, self).__setattr__(name, value)
You can't just use
setattr
, because that ends up calling your custom override again, and you're stuck in infinite recursion. (There's also__getattribute__
, which has the same purpose as__getattr__
, except that it is always called, not just for "not real" attributes.)By the way, try renaming yourget_dict
method to__dict__
, and then rundict(DialogFormField(placeholder="hi there!"))
.;)
-
@dgelessus , thanks for the info. I did do some playing with the *attr methods and getattribute method, but I was getting confused. As you mention, side effects start occurring. So I tried to do it in a way which I think I understand.
Now, it's sort of working I will try again.
With your comment about dict, not sure if I am doing something wrong or you wanted me to learn something :)
I did as you said regarding dict, but got the error message that DialogFormField is not iterable.
So I added an iter method asdef __iter__(self): for attr in self.flds: yield (attr , getattr(self, attr))
Then print dict(DialogFormField()) prints the dict :)
It was also nice to see the below work.
for item in DialogFormField(): print item
I know it's basic. But it's not for me, exciting to see classes work in naturally with Python as the built in classes. Gives you a new appreciation for the possibilities for elegant solutions that can be created with classes.
Again, thanks for your comments. I know I am a little off track from Pythonista. While its a learning exercise for me, I really think there is a place for a class like this that can help clean up parameter creation, but in a generic way as possible.
-
@dgelessus , I was having problems working out your suggestions. I think I got the functionality though, without overriding *attr methods.
But I am starting to question the wisdom of creating the class in the first place. It's difficult sometimes. You think you are on to something cool, then you are not :)
Oh, well. Needs more thought on my part.# coding: utf-8 import ui import dialogs import sys _fld_attrs = { 'type': None, 'key' : None, 'value' : '', 'title' : None, 'tint_color': None, 'icon' : None, 'placeholder': '', 'autocorrection' : False, 'autocapitalization' : False, } class DialogFormField (object): def __init__(self, **kwargs): ''' DialogFormField Just start of an idea to create an easy way to give more comlicated params to functions/methods some form of structured params. i could be off on the wrong track. But while the params look easy enough to a lot of libs, in practice they make for a lot code. also dot notation not avalible etc... Again, is not finished... just exploring ''' self.__dict__.update(_fld_attrs) # set the attrs for k in kwargs: if hasattr(self, k): setattr(self, k, kwargs[k]) def __iter__(self): for attr in self.__dict__: yield (attr , getattr(self, attr)) if __name__ == '__main__': flds = [] lst = ['First Name', 'Last Name', 'Age'] for f in lst: flds.append(dict(DialogFormField(title = f + ':', type = 'text' , placeholder = 'Enter ' + f , key = f, tint_color = 'red'))) results = dialogs.form_dialog(title = 'Test', fields = flds) print results
-
Nevermind,
__dict__
is actually not the special method for "convert to dictionary". Thought I was being smart there. The proper way to make your class dictionary-compatible would be to make it iterable (like you did) and implement all the mapping methods likekeys
,values
,items
, etc. -
@dgelessus , still good learning experience:)
-
I wil just declare I am an idiot. My lack of knowledge takes me on stupid journeys.if I had looked at dict class in more detail i would not been trying to write this class. Have dictviews also. But it's all been a learning process. After doing this, I feel a lot better equipped to try and understand dicts 100%