Re: Dispatch table of methods with various return value types

2020-11-27 Thread Loris Bennett
dn  writes:

> On 19/11/2020 02:13, Loris Bennett wrote:
>> dn  writes:
>>
>> Firsty, thanks for taking the time to write such a detailed reply.
>
> Bitte!
>
>
>> I have a method for manipulating the membership of groups such as:
>>
>>def execute(self, operation, users, group):
>>"""
>>Perform the given operation on the users with respect to the
>>group
>>"""
>>
>>action = {
>>'get': self.get,
>>'add': self.add,
>>'delete': self.delete,
>>}
>>
>>return action.get(operation)(users, group)
>>
>> The 'get' action would return, say, a dict of users attribute, whereas
>> the 'add/delete' actions would return, say, nothing, and all actions
>> could raise an exception if something goes wrong.
>>
>> The method which calls 'execute' has to print something to the terminal,
>> such as the attributes in the case of 'get' and 'OK' in the cases of
>> 'add/delete' (assuming no exception occurred).
>>
>> Is there a canonical way of dealing with a method which returns different
>> types of data, or should I just make all actions return the same data
>> structure so that I can generate a generic response?
>
>
> Is the problem caused by coding the first step before thinking of the 
> overall
> task? Try diagramming or pseudo-coding the complete solution (with 
> multiple
> approaches), ie the operations AND the printing and exception-handling.

 You could have a point, although I do have a reasonable idea of what the
 task is and coming from a Perl background, Python always feels a bit
 like pseudocode anyway (which is one of the things I like about Python).
>>>
>>> +1 the ease of Python, but can this be seductive?
>>>
>>> Per the comment about Perl/Python experience, the operative part is the
>>> "thinking", not the tool - as revealed in responses below...
>>>
>>> Sometimes we design one 'solution' to a problem, and forget (or 'brainwash'
>>> ourselves into thinking) that there might be 'another way'.
>>>
>>> It may/not apply in this case, but adjusting from a diagram-first 
>>> methodology,
>>> to the habit of 'jumping straight into code' exhibited by many colleagues,
>>> before readjusting back to (hopefully) a better balance; I felt that
>>> coding-first often caused me to 'paint myself into a corner' with some
>>> 'solutions, by being too-close to the code and not 'stepping back' to take a
>>> wider view of the design - but enough about me...
>>>
>>>
> Might it be more appropriate to complete not only the get but also its
> reporting, as a unit. Similarly the add and whatever happens after that; 
> and the
> delete, likewise.

 Currently I am already obtaining the result and doing the reporting in
 one method, but that makes it difficult to write tests, since it
 violates the idea that one method should, in general, just do one thing.
 That separation would seem appropriate here, since testing whether a
 data set is correctly retrieved from a database seems to be
 significantly different to  testing whether the
 reporting of an action is correctly laid out and free of typos.
>>>
>>> SRP = design thinking! +1
>>
>> I knew the idea, but I didn't now the TLA for it ;-)
>
> Yes, there are plenty of those!
>
> You may be interested in reading about "Clean Code", instigated (IIRC) by 
> "Uncle
> Bob" (Robert Martin). NB Python may/not be used for book-examples. Just the
> other day I came across "Clean Code in Python", Mariano Anaya, PacktPub, 
> 2018. I
> have yet to read it, but the contents page seemed to 'tick all the boxes'. The
> book is two years old, and IIRC he presented at EuroPython a few years before
> that (YouTube videos on-line - in case you prefer that medium, or want to 
> gain a
> flavor before spending money...). All of these TLAs, and others comprising the
> "SOLID Principles" appear in the ToC, along with plenty of others, eg YAGNI 
> and
> EAFP; plus some specific to Python, eg MRO.

I had a look at the Europython 2016 video and found it very instructive.
I'm a not very familiar with using exceptions, but when I have tried to
use them, its seems to have generated a lot of code clutter.  The
approach shown in the video seems to be an elegant solution for certain
category of exception handling code repetition.

>>> TDD = early testing! +1
>>>
>>> Agreed: The tasks are definitely separate. The first is data-related. The 
>>> second
>>> is about presentation.
>>>
>>> In keeping with the SRP philosophy, keep the split of execution-flow into 
>>> the
>>> three (or more) functional-tasks by data-process, but turn each of those 
>>> tasks
>>> into two steps/routines. (once the reporting routine following "add" has 
>>> been
>>> coded, and it comes time to implement "delete", it 

Re: Dispatch table of methods with various return value types

2020-11-19 Thread dn via Python-list

On 19/11/2020 02:13, Loris Bennett wrote:

dn  writes:

Firsty, thanks for taking the time to write such a detailed reply.


Bitte!



I have a method for manipulating the membership of groups such as:

   def execute(self, operation, users, group):
   """
   Perform the given operation on the users with respect to the
   group
   """

   action = {
   'get': self.get,
   'add': self.add,
   'delete': self.delete,
   }

   return action.get(operation)(users, group)

The 'get' action would return, say, a dict of users attribute, whereas
the 'add/delete' actions would return, say, nothing, and all actions
could raise an exception if something goes wrong.

The method which calls 'execute' has to print something to the terminal,
such as the attributes in the case of 'get' and 'OK' in the cases of
'add/delete' (assuming no exception occurred).

Is there a canonical way of dealing with a method which returns different
types of data, or should I just make all actions return the same data
structure so that I can generate a generic response?



Is the problem caused by coding the first step before thinking of the overall
task? Try diagramming or pseudo-coding the complete solution (with multiple
approaches), ie the operations AND the printing and exception-handling.


You could have a point, although I do have a reasonable idea of what the
task is and coming from a Perl background, Python always feels a bit
like pseudocode anyway (which is one of the things I like about Python).


+1 the ease of Python, but can this be seductive?

Per the comment about Perl/Python experience, the operative part is the
"thinking", not the tool - as revealed in responses below...

Sometimes we design one 'solution' to a problem, and forget (or 'brainwash'
ourselves into thinking) that there might be 'another way'.

It may/not apply in this case, but adjusting from a diagram-first methodology,
to the habit of 'jumping straight into code' exhibited by many colleagues,
before readjusting back to (hopefully) a better balance; I felt that
coding-first often caused me to 'paint myself into a corner' with some
'solutions, by being too-close to the code and not 'stepping back' to take a
wider view of the design - but enough about me...



Might it be more appropriate to complete not only the get but also its
reporting, as a unit. Similarly the add and whatever happens after that; and the
delete, likewise.


Currently I am already obtaining the result and doing the reporting in
one method, but that makes it difficult to write tests, since it
violates the idea that one method should, in general, just do one thing.
That separation would seem appropriate here, since testing whether a
data set is correctly retrieved from a database seems to be
significantly different to  testing whether the
reporting of an action is correctly laid out and free of typos.


SRP = design thinking! +1


I knew the idea, but I didn't now the TLA for it ;-)


Yes, there are plenty of those!

You may be interested in reading about "Clean Code", instigated (IIRC) 
by "Uncle Bob" (Robert Martin). NB Python may/not be used for 
book-examples. Just the other day I came across "Clean Code in Python", 
Mariano Anaya, PacktPub, 2018. I have yet to read it, but the contents 
page seemed to 'tick all the boxes'. The book is two years old, and IIRC 
he presented at EuroPython a few years before that (YouTube videos 
on-line - in case you prefer that medium, or want to gain a flavor 
before spending money...). All of these TLAs, and others comprising the 
"SOLID Principles" appear in the ToC, along with plenty of others, eg 
YAGNI and EAFP; plus some specific to Python, eg MRO.




TDD = early testing! +1

Agreed: The tasks are definitely separate. The first is data-related. The second
is about presentation.

In keeping with the SRP philosophy, keep the split of execution-flow into the
three (or more) functional-tasks by data-process, but turn each of those tasks
into two steps/routines. (once the reporting routine following "add" has been
coded, and it comes time to implement "delete", it may become possible to repeat
the pattern, and thus 're-use' the second-half...)

Putting it more formally: as the second-half is effectively 'chosen' at the same
time as the first, is the reporting-routine "dependent" upon the data-processor?

function get( self, ... )
self.get_data()
self.present_data()

function add( self, ... )
self.add_data()
self.report_success_fail()

...

Thus, the functional task can be tested independently of any reporting follow-up
(for example in "get"); whilst maintaining/multiplying SRP...


The above approach appeals to me a lot.  Slight downsides are that
such 'metafunctions' by necessity non-SRP functions and that, as there
would be no point writing tests for such functions, some 

Re: Dispatch table of methods with various return value types

2020-11-18 Thread Loris Bennett
dn  writes:

Firsty, thanks for taking the time to write such a detailed reply.

> On 17/11/2020 23:35, Loris Bennett wrote:
>> dn  writes:
>>
>>> On 17/11/2020 22:01, Loris Bennett wrote:
 Hi,

 I have a method for manipulating the membership of groups such as:

   def execute(self, operation, users, group):
   """
   Perform the given operation on the users with respect to the
   group
   """

   action = {
   'get': self.get,
   'add': self.add,
   'delete': self.delete,
   }

   return action.get(operation)(users, group)

 The 'get' action would return, say, a dict of users attribute, whereas
 the 'add/delete' actions would return, say, nothing, and all actions
 could raise an exception if something goes wrong.

 The method which calls 'execute' has to print something to the terminal,
 such as the attributes in the case of 'get' and 'OK' in the cases of
 'add/delete' (assuming no exception occurred).

 Is there a canonical way of dealing with a method which returns different
 types of data, or should I just make all actions return the same data
 structure so that I can generate a generic response?
>>>
>>>
>>> Is the problem caused by coding the first step before thinking of the 
>>> overall
>>> task? Try diagramming or pseudo-coding the complete solution (with multiple
>>> approaches), ie the operations AND the printing and exception-handling.
>>
>> You could have a point, although I do have a reasonable idea of what the
>> task is and coming from a Perl background, Python always feels a bit
>> like pseudocode anyway (which is one of the things I like about Python).
>
> +1 the ease of Python, but can this be seductive?
>
> Per the comment about Perl/Python experience, the operative part is the
> "thinking", not the tool - as revealed in responses below...
>
> Sometimes we design one 'solution' to a problem, and forget (or 'brainwash'
> ourselves into thinking) that there might be 'another way'.
>
> It may/not apply in this case, but adjusting from a diagram-first methodology,
> to the habit of 'jumping straight into code' exhibited by many colleagues,
> before readjusting back to (hopefully) a better balance; I felt that
> coding-first often caused me to 'paint myself into a corner' with some
> 'solutions, by being too-close to the code and not 'stepping back' to take a
> wider view of the design - but enough about me...
>
>
>>> Might it be more appropriate to complete not only the get but also its
>>> reporting, as a unit. Similarly the add and whatever happens after that; 
>>> and the
>>> delete, likewise.
>>
>> Currently I am already obtaining the result and doing the reporting in
>> one method, but that makes it difficult to write tests, since it
>> violates the idea that one method should, in general, just do one thing.
>> That separation would seem appropriate here, since testing whether a
>> data set is correctly retrieved from a database seems to be
>> significantly different to  testing whether the
>> reporting of an action is correctly laid out and free of typos.
>
> SRP = design thinking! +1

I knew the idea, but I didn't now the TLA for it ;-)

> TDD = early testing! +1
>
> Agreed: The tasks are definitely separate. The first is data-related. The 
> second
> is about presentation.
>
> In keeping with the SRP philosophy, keep the split of execution-flow into the
> three (or more) functional-tasks by data-process, but turn each of those tasks
> into two steps/routines. (once the reporting routine following "add" has been
> coded, and it comes time to implement "delete", it may become possible to 
> repeat
> the pattern, and thus 're-use' the second-half...)
>
> Putting it more formally: as the second-half is effectively 'chosen' at the 
> same
> time as the first, is the reporting-routine "dependent" upon the 
> data-processor?
>
>   function get( self, ... )
>   self.get_data()
>   self.present_data()
>
>   function add( self, ... )
>   self.add_data()
>   self.report_success_fail()
>
>   ...
>
> Thus, the functional task can be tested independently of any reporting 
> follow-up
> (for example in "get"); whilst maintaining/multiplying SRP...

The above approach appeals to me a lot.  Slight downsides are that
such 'metafunctions' by necessity non-SRP functions and that, as there
would be no point writing tests for such functions, some tools which try
to determine test coverage might moan.

>>> Otherwise the code must first decide which action-handler, and later,
>>> which result-handler - but aren't they effectively the same decision?
>>> Thus, is the reporting integral to the get (even if they are in
>>> separate routines)?
>>
>> I think you are right here.  Perhaps I should just ditch the dispatch
>> table.  Maybe that 

Re: Dispatch table of methods with various return value types

2020-11-17 Thread dn via Python-list

On 17/11/2020 23:35, Loris Bennett wrote:

dn  writes:


On 17/11/2020 22:01, Loris Bennett wrote:

Hi,

I have a method for manipulating the membership of groups such as:

  def execute(self, operation, users, group):
  """
  Perform the given operation on the users with respect to the
  group
  """

  action = {
  'get': self.get,
  'add': self.add,
  'delete': self.delete,
  }

  return action.get(operation)(users, group)

The 'get' action would return, say, a dict of users attribute, whereas
the 'add/delete' actions would return, say, nothing, and all actions
could raise an exception if something goes wrong.

The method which calls 'execute' has to print something to the terminal,
such as the attributes in the case of 'get' and 'OK' in the cases of
'add/delete' (assuming no exception occurred).

Is there a canonical way of dealing with a method which returns different
types of data, or should I just make all actions return the same data
structure so that I can generate a generic response?



Is the problem caused by coding the first step before thinking of the overall
task? Try diagramming or pseudo-coding the complete solution (with multiple
approaches), ie the operations AND the printing and exception-handling.


You could have a point, although I do have a reasonable idea of what the
task is and coming from a Perl background, Python always feels a bit
like pseudocode anyway (which is one of the things I like about Python).


+1 the ease of Python, but can this be seductive?

Per the comment about Perl/Python experience, the operative part is the 
"thinking", not the tool - as revealed in responses below...


Sometimes we design one 'solution' to a problem, and forget (or 
'brainwash' ourselves into thinking) that there might be 'another way'.


It may/not apply in this case, but adjusting from a diagram-first 
methodology, to the habit of 'jumping straight into code' exhibited by 
many colleagues, before readjusting back to (hopefully) a better 
balance; I felt that coding-first often caused me to 'paint myself into 
a corner' with some 'solutions, by being too-close to the code and not 
'stepping back' to take a wider view of the design - but enough about me...




Might it be more appropriate to complete not only the get but also its
reporting, as a unit. Similarly the add and whatever happens after that; and the
delete, likewise.


Currently I am already obtaining the result and doing the reporting in
one method, but that makes it difficult to write tests, since it
violates the idea that one method should, in general, just do one thing.
That separation would seem appropriate here, since testing whether a
data set is correctly retrieved from a database seems to be
significantly different to  testing whether the
reporting of an action is correctly laid out and free of typos.


SRP = design thinking! +1
TDD = early testing! +1

Agreed: The tasks are definitely separate. The first is data-related. 
The second is about presentation.


In keeping with the SRP philosophy, keep the split of execution-flow 
into the three (or more) functional-tasks by data-process, but turn each 
of those tasks into two steps/routines. (once the reporting routine 
following "add" has been coded, and it comes time to implement "delete", 
it may become possible to repeat the pattern, and thus 're-use' the 
second-half...)


Putting it more formally: as the second-half is effectively 'chosen' at 
the same time as the first, is the reporting-routine "dependent" upon 
the data-processor?


function get( self, ... )
self.get_data()
self.present_data()

function add( self, ... )
self.add_data()
self.report_success_fail()

...

Thus, the functional task can be tested independently of any reporting 
follow-up (for example in "get"); whilst maintaining/multiplying SRP...




Otherwise the code must first decide which action-handler, and later,
which result-handler - but aren't they effectively the same decision?
Thus, is the reporting integral to the get (even if they are in
separate routines)?


I think you are right here.  Perhaps I should just ditch the dispatch
table.  Maybe that only really makes sense if the methods being
dispatched are indeed more similar.  Since I don't anticipate having
more than half a dozen actions, if that, so an if-elif-else chain
wouldn't be too clunky.


An if...elif...else 'ladder' is logically-easy to read, but with many 
choices it may become logistically-complicated - even too long to 
display at-once on a single screen.


Whereas, the table is a more complex solution (see 'Zen of Python') that 
only becomes 'simple' with practice.


So, now we must balance the 'level(s)' of the team likely to maintain 
the program(me) against the evaluation of simple~complex. Someone with a 
ComSc background will have no trouble 

Re: Dispatch table of methods with various return value types

2020-11-17 Thread Loris Bennett
dn  writes:

> On 17/11/2020 22:01, Loris Bennett wrote:
>> Hi,
>>
>> I have a method for manipulating the membership of groups such as:
>>
>>  def execute(self, operation, users, group):
>>  """
>>  Perform the given operation on the users with respect to the
>>  group
>>  """
>>
>>  action = {
>>  'get': self.get,
>>  'add': self.add,
>>  'delete': self.delete,
>>  }
>>
>>  return action.get(operation)(users, group)
>>
>> The 'get' action would return, say, a dict of users attribute, whereas
>> the 'add/delete' actions would return, say, nothing, and all actions
>> could raise an exception if something goes wrong.
>>
>> The method which calls 'execute' has to print something to the terminal,
>> such as the attributes in the case of 'get' and 'OK' in the cases of
>> 'add/delete' (assuming no exception occurred).
>>
>> Is there a canonical way of dealing with a method which returns different
>> types of data, or should I just make all actions return the same data
>> structure so that I can generate a generic response?
>
>
> Is the problem caused by coding the first step before thinking of the overall
> task? Try diagramming or pseudo-coding the complete solution (with multiple
> approaches), ie the operations AND the printing and exception-handling.

You could have a point, although I do have a reasonable idea of what the
task is and coming from a Perl background, Python always feels a bit
like pseudocode anyway (which is one of the things I like about Python).

> Might it be more appropriate to complete not only the get but also its
> reporting, as a unit. Similarly the add and whatever happens after that; and 
> the
> delete, likewise.

Currently I am already obtaining the result and doing the reporting in
one method, but that makes it difficult to write tests, since it
violates the idea that one method should, in general, just do one thing.
That separation would seem appropriate here, since testing whether a
data set is correctly retrieved from a database seems to be
significantly different to  testing whether the
reporting of an action is correctly laid out and free of typos.

> Otherwise the code must first decide which action-handler, and later,
> which result-handler - but aren't they effectively the same decision?
> Thus, is the reporting integral to the get (even if they are in
> separate routines)?

I think you are right here.  Perhaps I should just ditch the dispatch
table.  Maybe that only really makes sense if the methods being
dispatched are indeed more similar.  Since I don't anticipate having
more than half a dozen actions, if that, so an if-elif-else chain
wouldn't be too clunky.

Cheers,

Loris

-- 
This signature is currently under construction.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: Dispatch table of methods with various return value types

2020-11-17 Thread dn via Python-list

On 17/11/2020 22:01, Loris Bennett wrote:

Hi,

I have a method for manipulating the membership of groups such as:

 def execute(self, operation, users, group):
 """
 Perform the given operation on the users with respect to the
 group
 """

 action = {
 'get': self.get,
 'add': self.add,
 'delete': self.delete,
 }

 return action.get(operation)(users, group)

The 'get' action would return, say, a dict of users attribute, whereas
the 'add/delete' actions would return, say, nothing, and all actions
could raise an exception if something goes wrong.

The method which calls 'execute' has to print something to the terminal,
such as the attributes in the case of 'get' and 'OK' in the cases of
'add/delete' (assuming no exception occurred).

Is there a canonical way of dealing with a method which returns different
types of data, or should I just make all actions return the same data
structure so that I can generate a generic response?



Is the problem caused by coding the first step before thinking of the 
overall task? Try diagramming or pseudo-coding the complete solution 
(with multiple approaches), ie the operations AND the printing and 
exception-handling.


Might it be more appropriate to complete not only the get but also its 
reporting, as a unit. Similarly the add and whatever happens after that; 
and the delete, likewise.


Otherwise the code must first decide which action-handler, and later, 
which result-handler - but aren't they effectively the same decision? 
Thus, is the reporting integral to the get (even if they are in separate 
routines)?

--
Regards =dn
--
https://mail.python.org/mailman/listinfo/python-list


Dispatch table of methods with various return value types

2020-11-17 Thread Loris Bennett
Hi,

I have a method for manipulating the membership of groups such as:

def execute(self, operation, users, group):
"""
Perform the given operation on the users with respect to the
group
"""

action = {
'get': self.get,
'add': self.add,
'delete': self.delete,
}

return action.get(operation)(users, group)

The 'get' action would return, say, a dict of users attribute, whereas
the 'add/delete' actions would return, say, nothing, and all actions
could raise an exception if something goes wrong.

The method which calls 'execute' has to print something to the terminal,
such as the attributes in the case of 'get' and 'OK' in the cases of
'add/delete' (assuming no exception occurred).

Is there a canonical way of dealing with a method which returns different
types of data, or should I just make all actions return the same data
structure so that I can generate a generic response?

Cheers,

Loris

-- 
This signature is currently under construction.
-- 
https://mail.python.org/mailman/listinfo/python-list