Single DB connection during class's lifetime. Metaclass,singletonand __new__() examples and references.
Ryan Johnson
rj.amdphreak at gmail.com
Mon Oct 15 12:16:38 EDT 2018
Thank you. That clears everything up.
Sent from Mail for Windows 10
From: Cameron Simpson
Sent: Saturday, October 13, 2018 6:06 PM
To: Ryan Johnson
Cc: python-list at python.org
Subject: Re: Single DB connection during class's lifetime. Metaclass,singletonand __new__() examples and references.
On 12Oct2018 13:28, Ryan Johnson <rj.amdphreak at gmail.com> wrote:
>Thanks for the clarification.
>
>If I am creating a class variable, are you suggesting I perform the “if it exists, great, otherwise make it” logic in the __init__ block or in the class definition block? Will that even run in a class definition?
The class definition code runs when the class is defined (as Python
reads it in your code).
The __init__ block runs once each time a new instance of the class is
initialised.
When do you _want_ this logic to run? That dictates where the logic
goes.
If you run this in the class definition code it pretty much will
unconditionally make a db connection. But in reality (a) you usually
want to defer making the connection until you need it to reduce resource
usage and (b) you often don't know enough to make the connection at
class definition time i.e. you don't know the database host, the
credentials, etc - they are often supplied to the initialiser (directly
or via some config file).
>I never see examples do anything besides assignment operations and flow
>control, although it would follow that if the block allows creation of
>strings (an object), it would allow creation of connection objects. On
>the other hand, the __init__ block seems like a natural place to put
>the cursor instantiation.
You can do anything that is sensible in the __init__ block - it is just
code. Your goal is to decide what is sensible.
Normally the initialiser mosts sets up various arrtributes to sane
initial values. It can do complex things, but is usually relatively
basic.
I'd note, as Thomas did, that the cursor is a control object associated
with a query. You can have multiple cursors on a connection, and you
often make one from a query, process the query results, then discard the
cursor. SO you routinely use several during the lifetime of a
connection.
Therefore you don't make cursors when you set up the connection; you
make them in association with queries.
>From this answer ( https://stackoverflow.com/questions/25577578/python-access-class-variable-from-instance/25577642#25577642 ) the pythonic way to access the class variable is using type(self), but doesn’t this access the local class’s variable, if someone subclasses my class? Can I specify my class variable via the class name itself? Example: instancevar = ClassName.classvar .
>I am hoping that because of the way python points labels to objects, this should give my instance an instance var that refers to the class var. Am I right?
_Usually_ I access class attributes (which you're calling variables, I
believe - they're not) via the instance:
def foo(self, blah=None):
if blah is None:
blah = foo.DEFAULT_BLAH_VALUE
... work with blah ...
As you suggest, this will find DEFAULT_BLAH_VALUE from the subclass
before it finds it from the superclass. Usually that is what I want -
the purpose of subclassing is to (possibly) override the aspects of the
superclass.
However, you _can_ always reach directly to a specific class to get a
value:
blah = MySuperCLass.DEFAULT_BLAH_VALUE
if that is sensible. All you're doing is changing the way in which the
name "DEFAULT_BLAH_VALUE" is found: do I use the instance's name lookup
or go somewhere direct?
In your case with a persistent database connection associated with a
class it would be best to make the "get a connection" logic a class
method because the "is there a connection" attribute is associated with
the class, not the instance.
Methods are, by default, "instance" methods: they are defined like this:
def method(self, ...):
and you largely work through "self", being the current instance. That is
its "context".
Class method are defined like this:
@classmethod
def method(cls, ...)
and instead of having an instance as context (with the conventional name
'self"), you have the class (with the conventional name "cls"). These
are for methods which _do_ _not_ care about the instance, just the
class. So in the case of your database connection, made on demand once
per class, you might go:
@classmethod
def conn(cls):
c = cls.connection
if c is None:
c = connect_to_the_db(.....)
cls.connection = c
return c
See that there's no "self" in here?
Then your instance methods can look like this:
def lookup(self, ....):
conn = self.conn()
cursor = conn.select(....)
... use the cursor to process the result ...
The instance finds the "conn" class method in the usual way: look in the
instance, then look in the class hierarchy.
This in itself is an argument against making the connection in the
__init__ block.
Does this help?
Cheers,
Cameron Simpson <cs at cskk.id.au>
More information about the Python-list
mailing list