Theme: Programming (& Python!) Fundamentals
Topic: Object-Orientation in Python and the Python Object Model
Keywords: Python, object orientation, data model, object model
Presenter | James Powell james@dutc.io |
Date | Friday, November 6, 2020 |
Time | 9:00 AM PST |
print("Let's get started!")
Pretend I have some library for controlling some hardware.
from lib import Scope
scope = Scope()
from lib import Scope
scope = Scope()
scope.connect('a::b::c')
scope.set_config(max_value=10)
scope.set_config(min_value=0, max_value=10)
scope.get_reading()
scope.restart()
scope.disconnect()
# TASK i: connect to a device
# TASK ii: set configuration on a device
with Scope.from_address('aa::bb::c') as dev:
pass
# with ctx():
# pass
# mgr = ctx()
# obj = mgr.__enter__()
# try:
# ...
# except Exception as e:
# mgr.__exit__(e, ...)
# else:
# mgr.__exit__(None, ...)
class Context:
def __enter__(self):
print('before the block')
def __exit__(self, *_):
print('after the block')
with Context():
print('inside the block')
print('inside the block')
print('inside the block')
from contextlib import contextmanager
class Scope:
def __init__(self, resource):
self.resource = resource
def __enter__(self):
print('Connecting to resource…')
self.connect(self.resource)
return self
def __exit__(self, *_):
print('Disonnect to resource…')
self.disconnect(self.resource)
@contextmanager
def config(self, config=None):
print(f'setting config to {config}')
try:
yield self
finally:
print(f'restoring old config')
connect = lambda *_: None
disconnect = lambda *_: None
CONFIG = 'some config'
ALTERNATE_CONFIG = 'some other config'
with Scope('aa::b::cc') as scope:
with scope.config(CONFIG):
...
with scope.config(ALTERNATE_CONFIG):
...
from collections import namedtuple
class ChOption(namedtuple('ChOption', 'channel position bandwidth coupling')):
def __new__(cls, channel, position, bandwidth=20, coupling='ac'):
return super().__new__(cls, channel, position, bandwidth, coupling)
@property
def commands(self):
yield f'CH{self.channel}:POSITION:{self.position}'
yield f'CH{self.channel}:BANDWIDTH:{self.bandwidth}'
yield f'CH{self.channel}:COUPLING:{self.coupling}'
def __str__(self):
return '\n'.join(self.commands)
CONFIG = {
ChOption(2, position=4),
ChOption(3, position=5),
ChOption(4, position=2, coupling='dc'),
}
for co in CONFIG:
for cmd in co.commands:
print(f'{cmd}')
# TASK iii: retrieve values from a device
from collections import namedtuple
from time import sleep
from numpy.random import bytes
from random import random
from contextlib import contextmanager
from queue import Queue
Result = namedtuple('Result', 'data time')
class Scope:
def __init__(self, resource):
self.resource = resource
self.queue = Queue()
def __enter__(self):
print('Connecting to resource…')
self.connect(self.resource)
return self
def __exit__(self, *_):
print('Disonnect to resource…')
self.disconnect(self.resource)
@contextmanager
def config(self, config=None):
print(f'setting config to {config}')
try:
yield self
finally:
print(f'restoring old config')
connect = lambda *_: None
disconnect = lambda *_: None
def read(self, size=10, wait=1):
sleep(wait)
return Result(bytes(size), random())
def submit(self, action):
self.queue.put(action)
async def run(self):
while not self.queue.empty():
action = self.queue.get()
try:
...
await asyncio.sleep(1)
except Exception:
await asyncio.sleep(10)
Read = namedtuple('Read', '')
with Scope('aa:bb::c') as sc:
sc.submit(Read())
sc.submit(Read())
sc.submit(Read())
sc.run()
# TASK iv: retrieve values under different scenarios