git.net

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Python refactoring question and create dynamic attributes


On 2019-06-23 10:44, Arup Rakshit wrote:
> 
>> On 23-Jun-2019, at 2:31 PM, Cameron Simpson <cs at cskk.id.au> wrote:
>> 
>> On 23Jun2019 13:26, Arup Rakshit <ar at zeit.io> wrote:
>>> In the below code:
>>> 
>>>   @classmethod
>>>   def find(self, id):
>>>       if isinstance(id, list):
>>>           rows = self.__table__().get_all(*id).run(self.__db__().conn)
>>>           result = []
>>>           for row in rows:
>>>               acategory = Category()
>>>               acategory.__dict__.update(row)
>>>               result.append(acategory)
>>>           return result
>>>       else:
>>>           adict = self.__table__().get(id).run(self.__db__().conn)
>>>           acategory = Category()
>>>           acategory.__dict__.update(adict)
>>>           return acategory
>>> 
>>> I have 2 questions:
>>> 
>>> 1. Is there any better way to create attributes in an object without using __dict__().update() or this is a correct approach?
>> 
>> setattr() is the usual approach, but that sets a single attribute at a time. If you have many then __dict__.update may be reasonable.
>> 
>> You should bear in mind that not all objects have a __dict__. It is uncommon, but if a class is defined with a __slots__ attribute then its instances have fixed attribute names and there is no __dict__. Also some builtin types have not __dict__. However, you likely know that the objects you are using have a __dict__, so you're probably good.
>> 
>> Also, __dict__ bypasses properties and descriptors. That might be important.
>> 
>>> 2. Can we get the same result what for row in rows: block is producing without killing the readability ?
>> 
>> Not obviously. It looks pretty direct to me.
>> 
>> Unless the Category class can be made to accept an attribute map in its __int__ method, then you might do some variable on:
>> 
>> result = [ Category(row) for row in rows ]
>> 
>> which is pretty readable.
>> 
>> BTW, @classmethods receive the class as the first argument, not an instance. So you'd normally write:
>> 
>> @classmethod
>> def find(cls, id):
>>   ?
>> 
> 
> What I know, is that first argument is reserved for the instance upon which it is called. It can be any name, so continued to use self. Yes these methods are class method intentionally. I am not aware of so far the naming rules of the first argument of a class or instance method.
> 
As Cameron wrote, the convention is that if it's an instance method you 
call its first parameter "self", whereas if it's a class method you call 
its first parameter "cls".

[snip]