with и анотации

„ Програмиране с Python“, ФМИ

14.04.2011

Пример с файлове

try:
    source_file = open(src, 'r')
    buffer = []
    try:
        buffer = source_file.readlines()
    finally:
        source_file.close()

    target_file = open(target, 'w')
    try:
        for line in reversed(buffer): 
            target_file.write(line)
    finally:
        target_file.close()
except IOError:
    print("Tough luck, junior")

Още един опит

buffer = []
try:
    with open(src) as source_file:
        buffer = source_file.readlines()
    with open(target) as target_file:
        for line in reversed(buffer):
            target_file.write(line)
except IOError:
    print("Much better, now, ain't it?")

with

with израз [as име]:
    блок

with нагледно


with open('/etc/passwd') as source_file:
    buffer = source_file.readlines()
print('Done!')

е същото като


source_file = open('/etc/passwd').__enter__()
try:
  buffer = source_file.readlines()
  source_file.__exit__(None, None, None)
except Exception:
  source_file.__exit__(*sys.exc_info())
print('Done!')

Малък пример

 
class Manager: 
    def __enter__(self): 
        print("I've been entered!")
        return 42 
    def __exit__(self, type, value, traceback): 
        print("I've been exited!")
 
with Manager() as something: 
    print("Am I inside?")
    print(something)
I've been entered!
Am I inside?
42
I've been exited!

with с няколко аргумента

with foo() as f, bar() as b:
    ...
with foo() as f:
    with bar() as b:
        ...

contextlib

Вграденият модул contextlib ни предлага три много полезни Context Manager-а:

closing

contextlib.closing вика метода close на обекта, с който работим, след изпълнение на блока:
class closing(object):
    def __init__(self, thing): self.thing = thing
    def __enter__(self): return thing
    def __exit__(self, type, value, traceback): self.thing.close()

…и ви позволява да пишете следното:

from contextlib import closing
import codecs

with closing(urllib.urlopen('http://www.python.org')) as page:
    for line in page:
        print(line)

contextmanager

contextmanager е декоратор, който превръща генератор функция в context manager:
from contextlib import contextmanager

@contextmanager
def entering(whom):
    print("I've been entered by {0}".format(whom))
    yield "ticket"
    print("I've been exited!")

with entering("someone") as something:
    print("Am I inside?")
    print(something)
I've been entered by someone
Am I inside?
ticket
I've been exited!

Pearl Jam FTW!!!

ContextDecorator

from contextlib import ContextDecorator

class mycontext(ContextDecorator):
    def __enter__(self):
        print('Starting')
        return self

    def __exit__(self, *exc):
        print('Finishing')
        return False

>>> @mycontext()
... def function():
...     print('The bit in the middle')

Анотации

def something(foo: 10, bar: 42):
    pass

print(something.__annotations__)

Достъпване на анотации

def something(foo: 10, bar: 42):
    pass

print(something.__annotations__)
{'foo': 10, 'bar': 42}

Анотиране на върната стойност

def something(foo: 10, bar: 42) -> 420:
    pass

print(something.__annotations__)
{'bar': 42, 'foo': 10, 'return': 420}

Анотиране на върната стойност

import inspect

def something(foo: 10, bar: 42) -> 420:
    pass

print(inspect.getfullargspec(something))

# FullArgSpec(args=['foo', 'bar'], varargs=None,
#    varkw=None, defaults=None, kwonlyargs=[],
#    kwonlydefaults=None,
#    annotations={'bar': 42, 'foo': 10, 'return': 420})

Демо

лишън!

Още въпроси?