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

Single DB connection during class's lifetime. Metaclass, singleton and __new__() examples and references.

Ryan Johnson <rj.amdphreak at gmail.com> writes:
> I am working on using mysql.connector in a class and have found an example of how to create a single connection that spans the lifetime of all instances of the class:
> https://softwareengineering.stackexchange.com/a/358061/317228 
> however, I do not understand a few things about the class, including
> 1. Why it is subclassed as an object: `class Postgres(object):` ? I thought classes were necessarily objects.

This obviously is for Python 2.

For historical reasons, Python 2 has two kinds of "class"es,
old style and new style classes. As new style classes were introduced
into Python 2, a need arose to distinguish them from old style classes:
a new style class can be recognized by the fact that is has "object"
in its inheritance graph.
I.e. "class Postgres(object)" indicates that "Postgres" is a new style

Python 3 only supports new style classes. Every class implicitely
inherits "object".

> 2. Why is this portion of code directly addressing the class, instead of using the `cls` reference variable?
> connection = Postgres._instance.connection = psycopg2.connect(**db_config)
> cursor = Postgres._instance.cursor = connection.cursor()

There is not real reason to use "Postgres" in this place instead of "cls".

> 3. And is it me or does anyone else think {anydb}.connector?s usage is messy and inelegant? Ex:
> print('connecting to PostgreSQL database...')
> connection = Postgres._instance.connection = psycopg2.connect(**db_config)
> cursor = Postgres._instance.cursor = connection.cursor()
> cursor.execute('SELECT VERSION()')
> db_version = cursor.fetchone()
> 	Why can?t we associate the focus of the connection with the connection itself, instead of creating a separate cursor object?

I think this is meant as an example to demonstrate how to
implement singleton database connections. As such, it has
print statements to demonstrates what is going on (i.e.
to convince you that several functions instantiating "postgres" indeed
share a common postgres connection.
In your own productive class, you would likely not have "print" statements.

> Also, within the code example, and in Python in general, why does there needs to be a __new__ constructor when there?s an __init__ constructor?

"__new__" essentially allocated the storage for a class instance,
"__init__" initializes this storage. You rarely need "__new__".
Typically, you need it only for classes where the amount
of storage initially allocated for a class instance
depends on the instance's value.
An example is a class inheriting from "tuple": A "tuple" directly
stores references to its components in itself - therefore, the amount
of storage depends on the number of components.

Most classes store the "content" of an instance in an extensible
structure of the instance (the so called "instance dict"). They
can use a standard "__new__" implementation and do not require
there own.

The example you reference could be rewritten to avoid the use of "__new__"
(and integrate its functionality instead into "__init__").
Note that "__new__" is a class method, "__init__" is (by default) an
instance method. This means, the the "cls" in "__new__" corresponds
to "self.__class__" in "__init__".

>I?ve read about the usage of singletons. It seems you could create singletons within  __init__ or __new__ .

You are right.