Различия между версиями 1 и 2
Версия 1 от 2020-11-24 12:46:52
Размер: 2341
Редактор: FrBrGeorge
Комментарий:
Версия 2 от 2020-11-24 17:29:31
Размер: 6648
Редактор: FrBrGeorge
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 36: Строка 36:
 * `open()`, `r`/`w`/`a` и т. п.
 * `.read()`/`.write()`/`.readline()`
 * файл как итератор, `.readlines()`
 * `.seek()`,`.tell()`
Строка 37: Строка 41:
  * `str`, `bytes` и `bytearray`
 * файл как итератор
 * файл и `with`
  * повтор: `str`, `bytes` и `bytearray`
  * `b`/`t`
 * файл и `with`, зачем нужно
Строка 43: Строка 47:
  * Кодировка: соответствие некоторого числа конкретному символу (например, описанному в [[https://r12a.github.io/uniview/|Unicode]])
  * Тысячи их
  * UTF-8: то ли один байт, то ли два :(
  * Однобайтные кодировки: без указания кодировки нельзя понять, что написано
  {{{#!highlight pycon
>>> txt = "Вопрос"
>>> print(*map(hex, map(ord, txt)))
0x412 0x43e 0x43f 0x440 0x43e 0x441
>>> txt.encode()
b'\xd0\x92\xd0\xbe\xd0\xbf\xd1\x80\xd0\xbe\xd1\x81'
>>> sys.getdefaultencoding()
'utf-8'
>>> txt.encode('utf-8')
b'\xd0\x92\xd0\xbe\xd0\xbf\xd1\x80\xd0\xbe\xd1\x81'
>>> txt.encode('WINDOWS-1251')
b'\xc2\xee\xef\xf0\xee\xf1'
>>> txt.encode('KOI8-R')
b'\xf7\xcf\xd0\xd2\xcf\xd3'
>>> txt.encode('WINDOWS-1251').decode('KOI8-R')
'бНОПНЯ'
  }}}
  * Представление строк внутри Python: т. н. «питоний unicode» (двухбайтовый)
   * Если в строке нет ни одного не-ASCII символа, она хранится побайтово, но это абсолютно прозрачно, кроме размера:
   {{{#!highlight pycon
>>> sys.getsizeof("qwe")
52
>>> sys.getsizeof("qwer")
53
>>> sys.getsizeof("qwert")
54
>>> sys.getsizeof("qwertЫ")
86
>>> sys.getsizeof("qwertЫs")
88
>>> sys.getsizeof("qwertЫsf")
  }}}
Строка 44: Строка 84:
 * '''TODO'''
Строка 50: Строка 90:
   {{{#!highlight pycon
>>> import pickle
>>> pickle.dumps(0x14131211)
b'\x80\x04\x95\x06\x00\x00\x00\x00\x00\x00\x00J\x11\x12\x13\x14.'
>>> pickle.dumps(0x14131211)[-5:]
b'\x11\x12\x13\x14.'
>>> du = pickle.dumps(123.123e20)
>>> du
b'\x80\x04\x95\n\x00\x00\x00\x00\x00\x00\x00GD\x84\xdb\x9b\xe5\x05\x1cP.'
>>> ud = pickle.loads(du)
>>> ud
1.23123e+22
>>> F = open("serialized", "bw")
>>> pickle.dump(100500, F)
>>> pickle.dump([1, "WER", None], F)
>>> pickle.dump(b"QWWER", F)
>>> F.close()
>>> F = open("serialized", "br")
>>> pickle.load(F)
100500
>>> pickle.load(F)
[1, 'WER', None]
>>> pickle.load(F)
b'QWWER'
>>> class C:
... A = 3
...
>>> c = C()
>>> du = pickle.dumps(c)
>>> ud = pickle.loads(du)
>>> ud
<__main__.C object at 0x7f0e60c502b0>
>>> ud.A
3
>>> ud = pickle.loads(du)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: Can't get attribute 'C' on <module '__main__' (<_frozen_importlib_external.SourceFileLoader object at 0x7f0e60c8bac0>)>
>>> class C:
... E = 100500
...
>>> ud = pickle.loads(du)
>>> ud
<__main__.C object at 0x7f0e60b50b20>
>>> ud.A
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute 'A'
>>> ud.E
100500
   }}}
Строка 54: Строка 145:
   * пример: заголовок PNG
Строка 56: Строка 146:
   * <!> последовательность байтов?    * последовательность байтов
  * Пример: [[WP:Portable_Network_Graphics#File_format|заголовок PNG]]
  {{{#!python
import struct
import zlib
import sys

HEADER = "8B"
CHUNK = "!I4s"
CRC = "!I"
IHDR = "!IIBBBBB"

def readpack(fmt, fle):
    return struct.unpack(fmt, fle.read(struct.calcsize(fmt)))

payload = b''
with open(sys.argv[1], "br") as f:
    png = readpack(HEADER, f)
    print(*map(hex, png))
    while (chunk := readpack(CHUNK, f))[1] != b"IEND":
        print(*chunk)
        data = f.read(chunk[0])
        crc = readpack(CRC, f)
        if chunk[1] == b"IHDR":
            w, h, bpp, col, comp, filt, i = struct.unpack(IHDR, data)
            print(f"{w}×{h}, {bpp=}, {col=}, {comp=}, {filt=}, {i=}")
        elif chunk[1] == b"IDAT":
            payload += data

print(len(payload), w, h, w*h)
payload = zlib.decompress(payload)
print(len(payload), w, h, w*h)
  }}}
Строка 60: Строка 182:
  {{{#!highlight pycon
>>> import dbm
>>> F = dbm.open("data.db", "c")
>>> F["qwe"] = "rty"
>>> F["asd"] = "zxcv"
>>> F["qerw"] = "werw"
>>> F["123"] = "123"
>>>
>>> F["asd"]
b'zxcv'
>>> F[b"asd"]
b'zxcv'
>>> F["Ы"] = "Ы"
>>> F["Ы"]
b'\xd0\xab'
>>> F.close()
>>> F = dbm.open("data.db", "r")
>>> F["qerw"]
b'werw'
>>> k = F.firstkey()
>>> k
b'\xd0\xab'
>>> while k:
... print(F[k])
... k = F.nextkey(k)
...
b'\xd0\xab'
b'rty'
b'zxcv'
b'werw'
b'123'
}}}

Работа с файлами

(Долг за прошлую лекцию — дескрипторы)

Оператор with

Например, with open("file") as f: …

Или (сначала сделать простой вариант, без __init__ и raise)

  •    1 class CM:
       2     def __init__(self, val = None):
       3         self.val = val
       4 
       5     def __enter__(self):
       6         print(">>>")
       7 
       8     def __exit__(self, *args):
       9         print("<<<",*(c for c in args if c))
      10         return self.val
      11 
      12 with CM(True) as f:
      13     print("Working")
      14     raise(SyntaxError("WTF?"))
      15 
      16 print("Done")
    

Далее см. contextlib.html

Просто файлы

В tutorial

  • open(), r/w/a и т. п.

  • .read()/.write()/.readline()

  • файл как итератор, .readlines()

  • .seek(),.tell()

  • текстовые и двоичные
    • повтор: str, bytes и bytearray

    • b/t

  • файл и with, зачем нужно

бНОПНЯ

  • Понятие кодировки. Unicode, UTF* и прочее
    • Кодировка: соответствие некоторого числа конкретному символу (например, описанному в Unicode)

    • Тысячи их
    • UTF-8: то ли один байт, то ли два :(

    • Однобайтные кодировки: без указания кодировки нельзя понять, что написано
         1 >>> txt = "Вопрос"
         2 >>> print(*map(hex, map(ord, txt)))
         3 0x412 0x43e 0x43f 0x440 0x43e 0x441
         4 >>> txt.encode()
         5 b'\xd0\x92\xd0\xbe\xd0\xbf\xd1\x80\xd0\xbe\xd1\x81'
         6 >>> sys.getdefaultencoding()
         7 'utf-8'
         8 >>> txt.encode('utf-8')
         9 b'\xd0\x92\xd0\xbe\xd0\xbf\xd1\x80\xd0\xbe\xd1\x81'
        10 >>> txt.encode('WINDOWS-1251')
        11 b'\xc2\xee\xef\xf0\xee\xf1'
        12 >>> txt.encode('KOI8-R')
        13 b'\xf7\xcf\xd0\xd2\xcf\xd3'
        14 >>> txt.encode('WINDOWS-1251').decode('KOI8-R')
        15 'бНОПНЯ'
        16 
      
    • Представление строк внутри Python: т. н. «питоний unicode» (двухбайтовый)
      • Если в строке нет ни одного не-ASCII символа, она хранится побайтово, но это абсолютно прозрачно, кроме размера:
           1 >>> sys.getsizeof("qwe")
           2 52
           3 >>> sys.getsizeof("qwer")
           4 53
           5 >>> sys.getsizeof("qwert")
           6 54
           7 >>> sys.getsizeof("qwertЫ")
           8 86
           9 >>> sys.getsizeof("qwertЫs")
          10 88
          11 >>> sys.getsizeof("qwertЫsf")
        
  • codecs

Типизированные файлы

  • объекты: чтение и запись объектов Python
    • pickle

      • pickle.dumps(obj) / pickle.dump(obj, file)

      • pickle.loads(bytes_object) / pickle.load(file)

           1 >>> import pickle
           2 >>> pickle.dumps(0x14131211)
           3 b'\x80\x04\x95\x06\x00\x00\x00\x00\x00\x00\x00J\x11\x12\x13\x14.'
           4 >>> pickle.dumps(0x14131211)[-5:]
           5 b'\x11\x12\x13\x14.'
           6 >>> du = pickle.dumps(123.123e20)
           7 >>> du
           8 b'\x80\x04\x95\n\x00\x00\x00\x00\x00\x00\x00GD\x84\xdb\x9b\xe5\x05\x1cP.'
           9 >>> ud = pickle.loads(du)
          10 >>> ud
          11 1.23123e+22
          12 >>> F = open("serialized", "bw")
          13 >>> pickle.dump(100500, F)
          14 >>> pickle.dump([1, "WER", None], F)
          15 >>> pickle.dump(b"QWWER", F)
          16 >>> F.close()
          17 >>> F = open("serialized", "br")
          18 >>> pickle.load(F)
          19 100500
          20 >>> pickle.load(F)
          21 [1, 'WER', None]
          22 >>> pickle.load(F)
          23 b'QWWER'
          24 >>> class C:
          25 ...     A = 3
          26 ... 
          27 >>> c = C()
          28 >>> du = pickle.dumps(c)
          29 >>> ud = pickle.loads(du)
          30 >>> ud
          31 <__main__.C object at 0x7f0e60c502b0>
          32 >>> ud.A
          33 3
          34 >>> ud = pickle.loads(du)
          35 Traceback (most recent call last):
          36   File "<stdin>", line 1, in <module>
          37 AttributeError: Can't get attribute 'C' on <module '__main__' (<_frozen_importlib_external.SourceFileLoader object at 0x7f0e60c8bac0>)>
          38 >>> class C:
          39 ...     E = 100500
          40 ... 
          41 >>> ud = pickle.loads(du)
          42 >>> ud
          43 <__main__.C object at 0x7f0e60b50b20>
          44 >>> ud.A
          45 Traceback (most recent call last):
          46   File "<stdin>", line 1, in <module>
          47 AttributeError: 'C' object has no attribute 'A'
          48 >>> ud.E
          49 100500
          50 
        
      • Pickling Class Instances

      • <!> небезопасно

  • структуры типа Си:
    • struct

    • Пример: заголовок PNG

         1 import struct
         2 import zlib
         3 import sys
         4 
         5 HEADER = "8B"
         6 CHUNK = "!I4s"
         7 CRC = "!I"
         8 IHDR = "!IIBBBBB"
         9 
        10 def readpack(fmt, fle):
        11     return struct.unpack(fmt, fle.read(struct.calcsize(fmt)))
        12 
        13 payload = b''
        14 with open(sys.argv[1], "br") as f:
        15     png = readpack(HEADER, f)
        16     print(*map(hex, png))
        17     while (chunk := readpack(CHUNK, f))[1] != b"IEND":
        18         print(*chunk)
        19         data = f.read(chunk[0])
        20         crc = readpack(CRC, f)
        21         if chunk[1] == b"IHDR":
        22             w, h, bpp, col, comp, filt, i = struct.unpack(IHDR, data)
        23             print(f"{w}×{h}, {bpp=}, {col=}, {comp=}, {filt=}, {i=}")
        24         elif chunk[1] == b"IDAT":
        25             payload += data
        26 
        27 print(len(payload), w, h, w*h)
        28 payload = zlib.decompress(payload)
        29 print(len(payload), w, h, w*h)
      
  • базы данных
    • dbm

    • Идея: интерфейс словаря (ключ:значение) + быстрый поиск под капотом
         1 >>> import dbm
         2 >>> F = dbm.open("data.db", "c")
         3 >>> F["qwe"] = "rty"
         4 >>> F["asd"] = "zxcv"
         5 >>> F["qerw"] = "werw"
         6 >>> F["123"] = "123"
         7 >>> 
         8 >>> F["asd"]
         9 b'zxcv'
        10 >>> F[b"asd"]
        11 b'zxcv'
        12 >>> F["Ы"] = "Ы"
        13 >>> F["Ы"]
        14 b'\xd0\xab'
        15 >>> F.close()
        16 >>> F = dbm.open("data.db", "r")
        17 >>> F["qerw"]
        18 b'werw'
        19 >>> k = F.firstkey()
        20 >>> k
        21 b'\xd0\xab'
        22 >>> while k:
        23 ...     print(F[k])
        24 ...     k = F.nextkey(k)
        25 ... 
        26 b'\xd0\xab'
        27 b'rty'
        28 b'zxcv'
        29 b'werw'
        30 b'123'
        31 
      
  • Файлы с известной структурой
    • Тысячи их, часть поддерживают файловый протокол, часть — нет

Д/З

TODO

LecturesCMC/PythonIntro2020/12_Files (последним исправлял пользователь FrBrGeorge 2020-11-28 21:10:29)