Генерирует штрих-коды, используя объекты-итераторы и итерируемые объекты

Сначала позвольте мне объяснить, какова цель этой программы: «штрих-код», как я его называю, состоит из трех частей:

  1. plant_idзнак равно[‘ATX’,’HOU’,’CHS’]
  2. Серийный номер: строка из 9 цифр
  3. мод 10 цифр: Цифра (в виде chr ()) от 0 до 9, которая случайным образом присваивается концу штрих-кода.

Итак, полный штрих-код будет выглядеть так:

‘ATX9784634072’: (ATX = plan_id, ‘978463407’ = серийный_номер, а ‘2’ – это 10-значный модификатор)

Заметка: для каждого серийного номера может быть только один штрих-код. Таким образом, в данном случае других штрих-кодов с серийным номером 978463407 нет. Идентификатор завода просто указывает на завод, который произвел товар. Таким образом, для каждого серийного номера есть 3 * 10 = 30 возможных штрих-кодов, и действителен только один.

Любой другой штрих-код с серийным номером 978463407 будет недействительным, независимо от его значения pland_id или его цифрового значения mod_10.

На данный момент у меня есть класс итератора BarcodeIterator, который выполняет итерацию только по серийным номерам в заданном диапазоне (аргументы запуска и остановки).

Затем у меня есть функция генератора bar_code_generator, которая принимает экземпляр BarcodeIterator () в качестве параметра для генерации полных штрих-кодов.

## Позвольте мне начать с объяснения структуры рассматриваемых штрих-кодов ## Штрих-код состоит из трех частей.  Идентификатор завода, ## серийный номер, затем цифра mod_10.  (Для целей этого ## кода я предполагаю, что это случайное число от 1 до 10 ## Пример: 'ATX9784634068', Plants =['ATX','HOU','DFW']
s_num0 = '978463406' s_num1 = '978463407' s_num2 = '978463408' класс BarcodeIterator: def __init __ (self, barcode, start, stop, plant_ID =['ATX','HOU','CHS']): self.plant = штрих-код[:3]
        self.serial_number = штрих-код[3:12]
        self.mod_10 = штрих-код[-1]
        self.start = int (self.serial_number) -start-1 self.stop = int (self.serial_number) + stop self.plant_ID = plant_ID def __next __ (self): self.start + = 1, если self.start> self.stop : поднять StopIteration else: start_string = str (self.start) result = start_string.zfill (9) вернуть результат def __iter __ (self): return self def bar_code_generator (iterObj, plant_ID =['ATX','HOU','CHS']): для bc в iterObj: для p_id в plant_ID: def get_mod (): x0 = '0', а x0 <= '9': yield x0 x0 = chr (ord (x0) +1) для цифры в get_mod (): barcode_tuple = (p_id, bc, digit) barcode_string = ''. join (barcode_tuple) yield barcode_string ## class Barcode: '' 'будет моим итеративным классом' '' ## def __init __ (self, barcode): ## self .barcode = штрих-код ## self.plant_id = штрих-код[:3]
## .... ## ## def __iter __ (self): ## return BarcodeIterator (if __name __ == '__ main__': bc_iter = BarcodeIterator (s_num0,1,1) bc_gen = bar_code_generator (bc_iter) bc_list =[bc for bc in bc_gen]
    print (bc_list) и результат будет следующим:

['ATX0004634050', 'ATX0004634051', 'ATX0004634052', 'ATX0004634053'
   , 'ATX0004634054', 'ATX0004634055', 'ATX0004634056', 'ATX0004634057'
   , 'ATX0004634058', 'ATX0004634059', 'HOU0004634050', 'HOU0004634051'
   , 'HOU0004634052', 'HOU0004634053', 'HOU0004634054', 'HOU0004634055'
   , 'HOU0004634056', 'HOU0004634057', 'HOU0004634058', 'HOU0004634059'
   , 'CHS0004634050', 'CHS0004634051', 'CHS0004634052', 'CHS0004634053', . . . it continues

Finally, my question (or plea for help) is this:

I want to:

clean this code up a lot: I would really like to have a BarcodeIterator() object and a Barcode() object (the iterable). So that each time I call an instance of Barcode() it returns the next valid Barcode... which brings me to my second question

As I have mentioned twice. There is only one valid barcode per serial number (hence, 30 possible barcodes). I haven't put an isValid() function in the scrip because I don't know where it would go.

I want to see each time the Barcode() object is called, it yields the next valid barcode without having to create a new object (if possible).

I hope this was clear. Any help will be greatly appreciated.

Please post here, but if you have vast experience in python and want to work with me on this you are more than welcome to pm me.

4 Answers
4

I'm a little too tired to make any ambitious suggestions, but I thought I'd recommend a few minor improvements.

Your BarcodeIterator class could be significantly neater by just using a generator function. Unless you have a complicated object state used in multiple different ways that also needs to be iterable (like if you're writing a data structure), I've found manually writing iterator classes to have a tendency to convolute code. Even then, the last structure I wrote had its __iter__ method as a generator function for simplicity. Instead, I'd use (after removing the un-used bits):

from typing import Iterator

def barcode_iterator(barcode: str, start: int, stop: int) -> Iterator[str]: serial_number = штрих-код[3:12]
    start = int (serial_number) - start stop = int (serial_number) + stop while start <= stop: start_string = str (start) result = start_string.zfill (9) вывести результат start + = 1

Это избавляет от необходимости настраивать состояние в инициализаторе, просто чтобы использовать его в одном методе. Это также избавляет вас от необходимости вручную бросать StopIteration.

Если вы хотите иметь Barcode итерируемый класс, который возвращает только допустимые результаты, его __iter__ метод может выглядеть примерно так:

class Barcode:
    def __iter__(self):
        return (code
                for code in barcode_iterator(...)
                if is_valid(code))  # Assuming the existence of an is_valid function

get_mod странно. То, что он вложен внутри функции, предполагает, что он использует что-то во включающей области. Однако это не так; он просто возвращает список строковых чисел. Цифры также никогда не меняются, так что это не имеет особого смысла как функция. Думаю, это один из редких случаев, когда map на самом деле самый подходящий инструмент:

def bar_code_generator(iterObj, plant_ID=['ATX', 'HOU', 'CHS']):
    for bc in iterObj:
        for p_id in plant_ID:
            for digit in map(str, range(10)):  # essentially (str(n) for n in range(10))
                barcode_tuple = (p_id, bc, digit)
                barcode_string = ''.join(barcode_tuple)
                yield barcode_string

Я также не стал бы использовать ['ATX','HOU','CHS'] как значение по умолчанию в функциях. Замените его на использование кортежа:

def bar_code_generator(iterObj, plant_ID=('ATX', 'HOU', 'CHS')):

Это небольшое изменение, и вы, вероятно, здесь не укусите, но если вы когда-нибудь случайно мутируете plant_ID, вы получите очень запутанное поведение, используя списки.

  • Мне нравится предложение карты.

    - Мэтью Даути


  • Хорошо, мне нравятся эти две функции! Я хочу поместить их в класс BarcodeIterator () и использовать в функции __next __ (). Проверьте, действительны ли штрих-коды, если да, верните в функции __next __ (). Затем я хочу вернуть объект BarcodeIterator в функции __iter __ () объекта Barcode ().

    - Мэтью Даути

  • @MatthewDoughty Первая показанная мною функция заменяет BarcodeIterator класс (или, по крайней мере, я хотел). Тогда вместо фильтрации в __next__, Я бы просто использовал выражение генератора и сделал бы что-нибудь вроде valid_codes = (code for code in barcode_iterator(...) if is_valid(code)). Я бы произвел неотфильтрованные результаты от одного генератора, затем второй генератор потреблял бы первый и при необходимости фильтровал. При этом __iter__ метод Barcode может быть просто def __iter__(self): return (code for code in barcode_iterator(...) if is_valid(code).

    - канцерогенат

Почему штрих-код отвечает за поиск дополнительных штрих-кодов? Это кажется действительно странным.

Помимо этого, здесь, похоже, много ненужного жонглирования итераторами, генераторами и классом штрих-кода.

def serial_strings(start, count):
    return (
        str(serial_num).zfill(9)
        for serial_num in range(start, start+count)
    )

def barcodes(serial_start=0, serial_count=1, plants=['ATX','HOU','CHS']):
    return (
        plant+serial+str(digit)
        for serial in serial_strings(serial_start,serial_count)
        for plant in plants
        for digit in range(10)
    )

if __name__=='__main__':
    print(list(barcodes(463405)))

  • Я вернусь к вам через секунду. с этим. Это микрокосм реальной проблемы, которую я не хочу обсуждать в Интернете. Но да. Учитывая штрих-код, я хочу найти другие предметы, которые были изготовлены прямо до и сразу после. Серийные номера присваиваются последовательно по времени.

    - Мэтью Даути

  • Таким образом, часть штрих-кода, содержащая серийный номер, является последовательной по времени. Итак, штрих-код: ATX4634051019 (Завод: ATX; серийный номер: 463405101; mod_10: 9) мог быть сделан за 2 секунды до HOU4634051027 (Завод: HOU; серийный номер: 463405102; mod_10: 7) и так далее. Итак, если я хочу найти предметы, сделанные примерно в то же время, что и мой, мне нужно отсканировать 30 возможных штрих-кодов для одного штрих-кода.

    - Мэтью Даути


Что-то вроде этого генерирует все возможные штрих-коды "рядом" с данным штрих-кодом:

import itertools as it

def barcode_generator(barcode, start, stop, plants=['ATX','HOU','CHS']):
    serial_number=int(barcode[3:12])
    start = serial_number - start
    stop = serial_number + stop

    for serial, plant, suffix in it.product(range(start, stop), plants, range(10)):
        yield f"{plant}{serial:09}{suffix}"

Его можно использовать так:

for bcode in barcode_generator('HOU1234567890', 1, 1):
    print(bcode)

Или, если вам нужен объект-генератор:

bcgen = barcode_generator('HOU1234567890', 1, 1)
print(next(bcgen))

Таким образом, часть штрих-кода с серийным номером является последовательной по времени. Итак, штрих-код: ATX4634051019 (Завод: ATX; серийный номер: 463405101; mod_10: 9) мог быть сделан за 2 секунды до HOU4634051027 (Завод: HOU; серийный номер: 463405102; mod_10: 7) и так далее. Следующий серийный номер будет 463405103, 463405104, 463405105, 463405106, 463405107 ...

Я не знаю ни их цифры mod_10, ни их plant_id.

Мне нужен объект-итератор, который генерирует потенциальные штрих-коды. Это BarcodeIterator (): следующая функция должна проверять, действителен ли каждый сгенерированный штрих-код, если это так, она возвращает его и переходит к следующему серийному номеру. (он не проверяет штрих-коды с тем же серийным номером)

Следующий объект Barcode ():

должен быть повторяемым. Он должен иметь iter() и возвращать следующий действительный штрих-код при повторении

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *