Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #86025 > unrolled thread

Best practice: Sharing object between different objects

Started bypfranken85@gmail.com
First post2015-02-21 04:15 -0800
Last post2015-02-24 11:14 +1100
Articles 10 — 9 participants

Back to article view | Back to comp.lang.python


Contents

  Best practice: Sharing object between different objects pfranken85@gmail.com - 2015-02-21 04:15 -0800
    Re: Best practice: Sharing object between different objects Dave Angel <davea@davea.name> - 2015-02-21 09:28 -0500
    Re: Best practice: Sharing object between different objects Paul Rubin <no.email@nospam.invalid> - 2015-02-21 09:18 -0800
    Re: Best practice: Sharing object between different objects Rob Gaddi <rgaddi@technologyhighland.invalid> - 2015-02-23 18:10 +0000
      Re: Best practice: Sharing object between different objects Michael Torrie <torriem@gmail.com> - 2015-02-23 11:36 -0700
        Re: Best practice: Sharing object between different objects sohcahtoa82@gmail.com - 2015-02-23 12:02 -0800
          Re: Best practice: Sharing object between different objects Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-02-23 20:13 +0000
          Re: Best practice: Sharing object between different objects Ian Kelly <ian.g.kelly@gmail.com> - 2015-02-23 13:39 -0700
          Re: Best practice: Sharing object between different objects Michael Torrie <torriem@gmail.com> - 2015-02-23 14:10 -0700
          Re: Best practice: Sharing object between different objects Chris Angelico <rosuav@gmail.com> - 2015-02-24 11:14 +1100

#86025 — Best practice: Sharing object between different objects

Frompfranken85@gmail.com
Date2015-02-21 04:15 -0800
SubjectBest practice: Sharing object between different objects
Message-ID<aacac55a-6779-4ad3-96f4-5332ff36a365@googlegroups.com>
Hello!

I have a best-practice question: Imagine I have several hardware devices that I work with on the same I2C bus and I am using the python smbus module for that purpose. The individual devices are sensors, ADC, DAC components. As I said, I would like to derive the corresponding classes from one common class, let's say I2CDevice, so that they can share the same bus connection (I don't want to do a import smbus, ..., self.bus = smbus.SMBus(1) all the time). Of course, I could just pass the the bus reference to each instance, but I am pretty sure that there must be a nicer way to do this.

In particular, I imagine the following: It should be possible that I have two classes, ADC_I2C, DAC_I2C which share the same base class. Once I create an instance of ADC_I2C or DAC_I2C it should check whether a bus object exists, if not, it should create one and the other class should be able to use this bus reference as well. Do you get my point? I am pretty sure that such a design pattern should exist, maybe also in the reference of DB connections? Unfortunately I did not find something like this.

Any hints are highly appreciated!

Thanks!

[toc] | [next] | [standalone]


#86039

FromDave Angel <davea@davea.name>
Date2015-02-21 09:28 -0500
Message-ID<mailman.18966.1424528921.18130.python-list@python.org>
In reply to#86025
On 02/21/2015 07:15 AM, pfranken85@gmail.com wrote:
> Hello!
>
> I have a best-practice question: Imagine I have several hardware devices that I work with on the same I2C bus and I am using the python smbus module for that purpose. The individual devices are sensors, ADC, DAC components. As I said, I would like to derive the corresponding classes from one common class, let's say I2CDevice, so that they can share the same bus connection (I don't want to do a import smbus, ..., self.bus = smbus.SMBus(1) all the time). Of course, I could just pass the the bus reference to each instance, but I am pretty sure that there must be a nicer way to do this.
>
> In particular, I imagine the following: It should be possible that I have two classes, ADC_I2C, DAC_I2C which share the same base class. Once I create an instance of ADC_I2C or DAC_I2C it should check whether a bus object exists, if not, it should create one and the other class should be able to use this bus reference as well. Do you get my point? I am pretty sure that such a design pattern should exist, maybe also in the reference of DB connections? Unfortunately I did not find something like this.
>

I think you should write the code (or at least a skeleton version).  I 
suspect the answer will become obvious to you, once you're not worrying 
about design patterns, or being java compatible.

Regardless of whether you inherit from a common base class, both classes 
can have an attribute with a "bus object" in it.  The question becomes 
who initializes it, and who decides to reuse the "same one".  Your 
wording doesn't make that the least bit clear to me;  maybe your sample 
code will.

Many times when you'd have a common base class in Java or C++, you just 
have to have a common member or two in Python.

On the other hand, once you start implementing, maybe it'll become 
obvious that there's enough shared code for a common base class.

The first question is whether an ADC "is-a" bus, or "has-a" bus.  Stated 
that way it sounds like you should have an attribute in ADC which is a 
bus object.

> Any hints are highly appreciated!
>
> Thanks!
>


-- 
DaveA

[toc] | [prev] | [next] | [standalone]


#86056

FromPaul Rubin <no.email@nospam.invalid>
Date2015-02-21 09:18 -0800
Message-ID<87sidzchdq.fsf@jester.gateway.pace.com>
In reply to#86025
pfranken85@gmail.com writes:
> ADC, DAC components. As I said, I would like to derive the
> corresponding classes from one common class, let's say I2CDevice, so
> that they can share the same bus connection (I don't want to do a
> import smbus, ..., self.bus = smbus.SMBus(1) all the time). 

I don't really understand the question but it sounds like you might
want a class variable:

    import smbus

    class I2CDevice
       bus = smbus.SMBus(1)
       def __init__ (self): ...

This puts the "bus" object into the I2CDevice class itself.  It is
created when the I2CDevice class is defined.  Methods wanting to access
it can then say

   do_something_with(I2CDevice.bus)

is that what you wanted?

[toc] | [prev] | [next] | [standalone]


#86250

FromRob Gaddi <rgaddi@technologyhighland.invalid>
Date2015-02-23 18:10 +0000
Message-ID<mcfqeb$5tb$1@dont-email.me>
In reply to#86025
On Sat, 21 Feb 2015 04:15:50 -0800, pfranken85 wrote:

> Hello!
> 
> I have a best-practice question: Imagine I have several hardware devices
> that I work with on the same I2C bus and I am using the python smbus
> module for that purpose. The individual devices are sensors, ADC, DAC
> components. As I said, I would like to derive the corresponding classes
> from one common class, let's say I2CDevice, so that they can share the
> same bus connection (I don't want to do a import smbus, ..., self.bus =
> smbus.SMBus(1) all the time). Of course, I could just pass the the bus
> reference to each instance, but I am pretty sure that there must be a
> nicer way to do this.
> 
> In particular, I imagine the following: It should be possible that I
> have two classes, ADC_I2C, DAC_I2C which share the same base class. Once
> I create an instance of ADC_I2C or DAC_I2C it should check whether a bus
> object exists, if not, it should create one and the other class should
> be able to use this bus reference as well. Do you get my point? I am
> pretty sure that such a design pattern should exist, maybe also in the
> reference of DB connections? Unfortunately I did not find something like
> this.
> 
> Any hints are highly appreciated!
> 
> Thanks!

So my experience doing similar work is with VMEBus, but if I were trying 
to do what you're doing, I'd take advantage of the fact that hardware 
isn't nearly as abstract as software.  SMBus(1) represents three physical 
contiguous pieces of copper on a PCB somewhere.

So I'd solve it with module level global variables.  It's semi-frowned 
upon on software stuff because it creates an unintentional shared state 
between different modules, but you really HAVE a shared state, so it 
needs to be dealt with.

So I'd put your ADC and DAC in the same package, whether all in one file 
or all in a package folder, and I'd give that package a:

def getSMBus(busnumber):

that takes care of the management of only creating each bus once.

Then I'd give each class a:

def __init__(busnumber):
  self.bus = getSMBus(busnumber)

You could commonize that by deriving both classes from a common ancestor 
(all my VME modules derive from a common Region), but with only one piece 
of shared code between I don't think I'd bother.  If you did, you could 
make the getSMBus code a classmethod just to make clear the lack of 
dependency on individual instances, but that starts to be code for code's 
sake.

-- 
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order.  See above to fix.

[toc] | [prev] | [next] | [standalone]


#86254

FromMichael Torrie <torriem@gmail.com>
Date2015-02-23 11:36 -0700
Message-ID<mailman.19095.1424717125.18130.python-list@python.org>
In reply to#86250
On 02/23/2015 11:10 AM, Rob Gaddi wrote:
> So I'd solve it with module level global variables.  It's semi-frowned 
> upon on software stuff because it creates an unintentional shared state 
> between different modules, but you really HAVE a shared state, so it 
> needs to be dealt with.

I would also do it with a module attribute.  In my mind that's exactly
the right way to go.

But I disagree that it's frowned on or a bad thing. A module is a
completely appropriate place to store state.  In fact a module is an
object, but a special one that can only be instantiated once.  So as far
as patterns go, a module is a singleton. Almost any time in Python you
have something that you want to have exactly one instance of in your
program, you don't want to define a class but rather just use a module.

Any code in a module can be considered the constructor. It executes only
once in your program when the module is first imported, no matter how
many times its imported after that.

I often use a module to store configuration that is shared across
modules in my projects.

[toc] | [prev] | [next] | [standalone]


#86259

Fromsohcahtoa82@gmail.com
Date2015-02-23 12:02 -0800
Message-ID<ac52606e-f85f-4e94-8dac-6556e28821be@googlegroups.com>
In reply to#86254
On Monday, February 23, 2015 at 10:45:59 AM UTC-8, Michael Torrie wrote:
> On 02/23/2015 11:10 AM, Rob Gaddi wrote:
> > So I'd solve it with module level global variables.  It's semi-frowned 
> > upon on software stuff because it creates an unintentional shared state 
> > between different modules, but you really HAVE a shared state, so it 
> > needs to be dealt with.
> 
> I would also do it with a module attribute.  In my mind that's exactly
> the right way to go.
> 
> But I disagree that it's frowned on or a bad thing. A module is a
> completely appropriate place to store state.  In fact a module is an
> object, but a special one that can only be instantiated once.  So as far
> as patterns go, a module is a singleton. Almost any time in Python you
> have something that you want to have exactly one instance of in your
> program, you don't want to define a class but rather just use a module.
> 
> Any code in a module can be considered the constructor. It executes only
> once in your program when the module is first imported, no matter how
> many times its imported after that.
> 
> I often use a module to store configuration that is shared across
> modules in my projects.

That behavior always trips me up.  My intuition tells me that every time you import a module, it re-runs the code in the module.  So if I had a simple module named myModule.py that had a single line with `myInt = 1`, then I would *EXPECT* this behavior:

>>> import myModule
>>> myModule.myInt
1
>>> myModule.myInt = 2
>>> myModule.myInt
2
>>> import myModule
>>> myModule.myInt
1

It seems slightly counter-intuitive, but the *ACTUAL* behavior (where the final line prints 2) does allow for something nice: Easy use of global variables.

What's REALLY interesting is that this happens:

>>> import myModule
>>> myModule.myInt
1
>>> myModule.myInt = 2
>>> myModule.myInt
2
>>> del myModule
>>> import myModule
>>> myModule.myInt
2

I would REALLY expect that deleting the module object and then re-importing would reset that variable.  And then...

>>> del myModule.myInt
>>> del myModule
>>> import myModule
>>> myModule.myInt
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'myInt'

So yeah...modules are really only loaded once unless you use reload/imp.reload/importlib.reload.

But yeah, it seems slightly counter-intuitive to me at first, but certainly has its uses.

[toc] | [prev] | [next] | [standalone]


#86260

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2015-02-23 20:13 +0000
Message-ID<mailman.19099.1424722435.18130.python-list@python.org>
In reply to#86259
On 23/02/2015 20:02, sohcahtoa82@gmail.com wrote:
> On Monday, February 23, 2015 at 10:45:59 AM UTC-8, Michael Torrie wrote:
>> On 02/23/2015 11:10 AM, Rob Gaddi wrote:
>>> So I'd solve it with module level global variables.  It's semi-frowned
>>> upon on software stuff because it creates an unintentional shared state
>>> between different modules, but you really HAVE a shared state, so it
>>> needs to be dealt with.
>>
>> I would also do it with a module attribute.  In my mind that's exactly
>> the right way to go.
>>
>> But I disagree that it's frowned on or a bad thing. A module is a
>> completely appropriate place to store state.  In fact a module is an
>> object, but a special one that can only be instantiated once.  So as far
>> as patterns go, a module is a singleton. Almost any time in Python you
>> have something that you want to have exactly one instance of in your
>> program, you don't want to define a class but rather just use a module.
>>
>> Any code in a module can be considered the constructor. It executes only
>> once in your program when the module is first imported, no matter how
>> many times its imported after that.
>>
>> I often use a module to store configuration that is shared across
>> modules in my projects.
>
> That behavior always trips me up.  My intuition tells me that every time you import a module, it re-runs the code in the module.  So if I had a simple module named myModule.py that had a single line with `myInt = 1`, then I would *EXPECT* this behavior:
>
>>>> import myModule
>>>> myModule.myInt
> 1
>>>> myModule.myInt = 2
>>>> myModule.myInt
> 2
>>>> import myModule
>>>> myModule.myInt
> 1
>
> It seems slightly counter-intuitive, but the *ACTUAL* behavior (where the final line prints 2) does allow for something nice: Easy use of global variables.
>
> What's REALLY interesting is that this happens:
>
>>>> import myModule
>>>> myModule.myInt
> 1
>>>> myModule.myInt = 2
>>>> myModule.myInt
> 2
>>>> del myModule
>>>> import myModule
>>>> myModule.myInt
> 2
>
> I would REALLY expect that deleting the module object and then re-importing would reset that variable.  And then...
>
>>>> del myModule.myInt
>>>> del myModule
>>>> import myModule
>>>> myModule.myInt
> Traceback (most recent call last):
>    File "<stdin>", line 1, in <module>
> AttributeError: 'module' object has no attribute 'myInt'
>
> So yeah...modules are really only loaded once unless you use reload/imp.reload/importlib.reload.
>
> But yeah, it seems slightly counter-intuitive to me at first, but certainly has its uses.
>

Rule 1) Don't expect anything of Python, always read the docs.
Rule 2) If in doubt always refer to rule 1)

-- 
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#86263

FromIan Kelly <ian.g.kelly@gmail.com>
Date2015-02-23 13:39 -0700
Message-ID<mailman.19100.1424724040.18130.python-list@python.org>
In reply to#86259
On Mon, Feb 23, 2015 at 1:02 PM,  <sohcahtoa82@gmail.com> wrote:
> What's REALLY interesting is that this happens:
>
>>>> import myModule
>>>> myModule.myInt
> 1
>>>> myModule.myInt = 2
>>>> myModule.myInt
> 2
>>>> del myModule
>>>> import myModule
>>>> myModule.myInt
> 2
>
> I would REALLY expect that deleting the module object and then re-importing would reset that variable.

Even though you deleted the module locally, it's still referenced in
the sys.modules cache (as well as in any other place where it might
have been imported). That's the place you need to delete it from if
you really want to re-execute it.

>>> import myModule
>>> myModule.myInt
1
>>> myModule.myInt = 2
>>> myModule.myInt
2
>>> import sys
>>> del sys.modules['myModule']
>>> import myModule
>>> myModule.myInt
1

[toc] | [prev] | [next] | [standalone]


#86270

FromMichael Torrie <torriem@gmail.com>
Date2015-02-23 14:10 -0700
Message-ID<mailman.19102.1424725814.18130.python-list@python.org>
In reply to#86259
On 02/23/2015 01:02 PM, sohcahtoa82@gmail.com wrote:
> That behavior always trips me up.  My intuition tells me that every
> time you import a module, it re-runs the code in the module.  So if I
> had a simple module named myModule.py that had a single line with
> `myInt = 1`, then I would *EXPECT* this behavior:

Basically your intuition is wrong, but I'm not really sure why you think
this in the first place, especially if you're familiar with design
patterns.  A module is a singleton.  Plain and simple.  If you expect a
module to reinstantiate something every time you import it, then what
you want is a class, not a module.

Even if you think of modules like C header files, as far as use goes,
you wouldn't be too far wrong.  Generally speaking header files are
processed only once no matter how many times they are included (at least
the common ones with #ifdef fences in them).

I can see how coming from PHP would trip you up, though.  Of course I
never got the hang of include vs include_once vs require vs require_once.

[toc] | [prev] | [next] | [standalone]


#86278

FromChris Angelico <rosuav@gmail.com>
Date2015-02-24 11:14 +1100
Message-ID<mailman.19108.1424736906.18130.python-list@python.org>
In reply to#86259
On Tue, Feb 24, 2015 at 8:10 AM, Michael Torrie <torriem@gmail.com> wrote:
> On 02/23/2015 01:02 PM, sohcahtoa82@gmail.com wrote:
>> That behavior always trips me up.  My intuition tells me that every
>> time you import a module, it re-runs the code in the module.  So if I
>> had a simple module named myModule.py that had a single line with
>> `myInt = 1`, then I would *EXPECT* this behavior:
>
> I can see how coming from PHP would trip you up, though.  Of course I
> never got the hang of include vs include_once vs require vs require_once.

If you think of "import" as "go and grab this file of code and run it"
(like PHP's include or a preprocessor #include directive), then yes,
you would expect that. But think of it, instead, as "give me access to
this feature". If that feature doesn't yet exist, Python will go and
fetch it up; but if it does, yay! You now have access, really quickly
and easily.

ChrisA

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web