Double Context Entry¶
Double context entry is a pattern you will see throughout DFFML. It’s used almost everywhere for consistencies sake.
Note
This was covered in the 2021-02-016 Weekly Sync meeting: https://youtu.be/OY_OfqB7rkY?t=657 (until 19:12).
DFFML uses asyncio
heavily, as such when we talk about entering or exiting
contexts, we are always talking about the async
context unless explicitly
stated.
Rules of the double context entry pattern¶
All objects are comprised of two classes
The parent
Usually responsible for saving / loading files, creating initial connections to databases.
The context (Which always have the suffix, “Context”)
Usually responsible for transactions within a database, locks on sub resources, etc.
The methods of an object should reside in it’s context.
Benefits of using this pattern¶
Many network attached resources will fall into this pattern. By applying it uniformly, we make it so all classes have a future proof place to load network resources when / if needed.
Example - Model¶
You can also keep model or sources loaded by passing in their contexts. The advantage of this method is that we as the caller can control when models are saved and loaded, and when sources are opened / closed (for example if they are backed by a file).
model.py
import asyncio
from dffml import *
model = SLRModel(
features=Features(Feature("Years", int, 1),),
predict=Feature("Salary", int, 1),
location="tempdir",
)
async def main():
# Load model and source using double context entry pattern
# Here we create a memory backed source. Equivlant to what the above example
# does behind the scenes when passing in dict objects.
async with model, MemorySource(
records=[
Record(i, data={"features": {"Years": i}}) for i in range(6, 8)
]
) as source:
async with model() as mctx, source() as sctx:
# Train the model
await train(
mctx,
{"Years": 0, "Salary": 10},
{"Years": 1, "Salary": 20},
{"Years": 2, "Salary": 30},
{"Years": 3, "Salary": 40},
)
# Make predictions
async for i, features, prediction in predict(mctx, sctx):
features["Salary"] = round(prediction["Salary"]["value"])
print(features)
asyncio.run(main())
$ python model.py
{'Years': 6, 'Salary': 70}
{'Years': 7, 'Salary': 80}