Can someone explain me this code?

It’s an example from SQLAlchemy:

# create session and add objects
with Session(engine) as session, session.begin():
    session.add(some_object)
    session.add(some_other_object)
# inner context calls session.commit(), if there were no exceptions
# outer context calls session.close()

https://docs.sqlalchemy.org/en/20/orm/session_basics.html#framing-out-a-begin-commit-rollback-block

How with Session(engine) as session, session.begin(): exactly works?

with Session(engine) as session runs session = Session(engine).__enter__(), then you run session.begin().__enter__.

It’s shorthand for

with Session(engine) as session:
    with session.begin():
        session.add(some_object)
        session.add(some_other_object)

Honestly I’ve never seen something like this before either.

1 Like

Have a look at this example, hopefully the parallels are clear enough to be illustrative:

# context_manager_example.py
class CM:
    def __init__(self, name):
        self.name = name
        print('CM.init:', name)

    def __enter__(self):
        print('CM.enter:', self.name)
        return self

    def __exit__(self, *exc):
        print('CM.exit:', self.name, exc)
        return

    def child(self, name):
        print('CM.child:', self.name)
        return type(self)('.'.join([self.name, name]))


with CM('parent') as cm, cm.child('child'):
    pass
$ python3 context_manager_example.py 
CM.init: parent
CM.enter: parent
CM.child: parent
CM.init: parent.child
CM.enter: parent.child
CM.exit: parent.child (None, None, None)
CM.exit: parent (None, None, None)
3 Likes

Hello,

The answer is actually just above where this script is shown. It is a succinct version of this:

# create session and add objects
with Session(engine) as session:
    with session.begin():
        session.add(some_object)
        session.add(some_other_object)
    # inner context calls session.commit(), if there were no exceptions
# outer context calls session.close()

Note that the context manager is flexible enough that you can concatanate operations. So, instead of rewriting the with context manager again below, you can add the instruction in series, separated by a comma.

Here is another example. Suppose that you wanted to open two files to add / write some text to them, you can do so by this (note the concatanation of the two operations in series):

with open(file1_path, 'w') as f1, open(file2_path, 'w') as f2:

    f1.write('Today is a great day!')
    f2.write('Today is an awesome day!')

… as opposed to:

with open(file1_path, 'w') as f1:
    f1.write('Today is a great day!')

with open(file2_path, 'w') as f2
    f2.write('Today is an awesome day!')

It also helps if you understand some theory. Here are two links that may help in understanding:

Context Managers and Python’s with Statement – Real Python

27. Context Managers — Python Tips 0.1 documentation

Ty, it explains very well how it works. I also found the official docs:

With more than one item, the context managers are processed as if multiple with statements were nested:

with A() as a, B() as b:
SUITE

is semantically equivalent to:

with A() as a:
with B() as b:
SUITE

I must admit that, even if I read carefully that part (I was also convinced that it worked as @onePythonUser wrote, and not that the statements are nested), I hardly imagined that I could use the first target variable in the second expression. Very powerful and neat.