Python: передача переменной экземпляра в метод класса - PullRequest
0 голосов
/ 06 декабря 2018

Я использую xlsxwriter, и я создал класс, в котором я создал рабочую книгу.Затем я добавил 2 листа.Теперь я написал метод, который записывает данные на одну из таблиц, но теперь я хотел бы использовать его на обеих таблицах.Это простой пример для объяснения ситуации:

import xlsxwriter

class ExcelWorkbook():
    def __init__(self, filename):
        self.wb = xlsxwriter.Workbook(filename)
        self.ws1 = self.wb.add_worksheet('Num')
        self.ws1LineCount = 0
        self.ws2 = self.wb.add_worksheet('Result')
        self.ws2LineCount = 0

    def write_data(self, data, title):        
        self.ws1.write_row(self.ws1LineCount, 0, title)
        self.ws1LineCount += 1
        self.ws1.write_row(self.ws1LineCount, 0, data)
        self.ws1LineCount += 1

xlsxWorkbook = ExcelWorkbook('Test2.xlsx')
numArr = (0.000000520593523979187, 13.123456789, 1.789456, 0.002345, 0.00123, 1)
titleBar = ('Date', 'quantity', 'Average [m]', 'Standard Dev [m]', 'Test', 'Success')
xlsxWorkbook.write_data(numArr, titleBar)

Теперь я хотел бы использовать метод write_data для обоих листов, поэтому я решил передать лист в качестве параметра, но, к сожалению,это не так просто, так как я не могу передать переменную экземпляра self.ws1 или self.ws2.

Итак, вопрос: как я могу это сделать?

Я придумал очень неприятное решение, подобное этому:

def write_data(self, data, title, instance = 'ws1'):
    if instance == 'ws1':
        instance = self.ws1
        lineCounter = self.ws1LineCount
    elif instance == 'ws2':
        instance = self.ws2
        lineCounter = self.ws2LineCount

    instance.write_row(self.ws1LineCount, 0, title)
    lineCounter += 1
    instance.write_row(self.ws1LineCount, 0, data)
    lineCounter += 1

но, честно говоря, оно мне не нравится.Есть ли правильный способ сделать это или это совершенно неразумно?

Ответы [ 4 ]

0 голосов
/ 06 декабря 2018

Может быть, вам стоит подумать о наличии дополнительного класса ExcelWorksheet, чтобы поместить всю связанную с ними логику в:

class ExcelWorksheet(object):
    def __init__(self, workbook, name):
        self.wb = workbook
        self.ws = self.wb.add_worksheet(name)
        self.wsLineCount = 0

    def write_data(self, data, title):        
        self.ws.write_row(self.wsLineCount, 0, title)
        self.wsLineCount += 1
        self.ws.write_row(self.wsLineCount, 0, data)
        self.wsLineCount += 1

Таким образом, вы можете изменить свой код следующим образом:

class ExcelWorkbook(object):
    def __init__(self, filename):
        self.wb = xlsxwriter.Workbook(filename)
        self.ws1 = ExcelWorksheet(self.wb, 'Num')
        self.ws2 = ExcelWorksheet(self.wb, 'Result')


xlsxWorkbook = ExcelWorkbook('Test2.xlsx')
numArr = (0.000000520593523979187, 13.123456789, 1.789456, 0.002345, 0.00123, 1)
titleBar = ('Date', 'quantity', 'Average [m]', 'Standard Dev [m]', 'Test', 'Success')
xlsxWorkbook.ws1.write_data(numArr, titleBar)
xlsxWorkbook.ws2.write_data(numArr, titleBar)
0 голосов
/ 06 декабря 2018

Я бы сделал что-то вроде этого:

from collections import defaultdict
import xlsxwriter

class ExcelWorkbook():
    def __init__(self, filename):
        self.wb = xlsxwriter.Workbook(filename)

        self.ws1 = self.wb.add_worksheet('Num')
        self.ws2 = self.wb.add_worksheet('Result')
        self._line_counts = defaultdict(int)

    def write_data(self, ws, data, title):
        self._write_row(ws, title)
        self._write_row(ws, data)

    def _write_row(self, ws, content):
        ws.write_row(self._line_counts[ws], 0, content)
        self._line_counts[ws] += 1

xlsxWorkbook = ExcelWorkbook('Test2.xlsx')
numArr = (0.000000520593523979187, 13.123456789, 1.789456, 0.002345, 0.00123, 1)
titleBar = ('Date', 'quantity', 'Average [m]', 'Standard Dev [m]', 'Test', 'Success')
xlsxWorkbook.write_data(xlsxWorkbook.ws1, numArr, titleBar)
xlsxWorkbook.write_data(xlsxWorkbook.ws2, numArr, titleBar)

Используя defaultdict, вам не нужно явно сохранять переменную счетчика строк для каждого рабочего листа.Функция write_data принимает новый параметр ws, чтобы вы могли задать рабочий лист, в который следует записать.Запись строки может быть выделена в отдельный метод для уменьшения дублирования кода.

Это отвечает на ваш вопрос?

Редактировать:

значение по умолчаниюне может получить доступ к self, но вы можете обойти это довольно легко:

def write_data(self, data, title, ws=None):
        if ws is None:            
            ws = self.ws1
        self._write_row(ws, title)
        self._write_row(ws, data)
0 голосов
/ 06 декабря 2018

Вместо блока if лучше использовать workbook.get_worksheet_by_name() метод

def write_data(self, data, title, ws = 'Num'):
    wsheet = self.wb.get_worksheet_by_name(ws)
    wsheet.write_row(self.ws1LineCount, 0, title)
    lineCounter += 1
    wsheet.write_row(self.ws1LineCount, 0, data)
    lineCounter += 1

EDIT: или вы можете использовать функцию getattr (), например

def write_data(self, data, title, ws = 'ws1'):
    wsheet = getattr(self, ws, self.ws1))
    wsheet.write_row(self.ws1LineCount, 0, title)
    lineCounter += 1
    wsheet.write_row(self.ws1LineCount, 0, data)
    lineCounter += 1
0 голосов
/ 06 декабря 2018

С помощью vars (self) вы можете получить доступ к любому элементу объекта в качестве словаря.

Тогда vars (self) ["ws1"] будет похож на self.ws1 и vars (self) ["ws2"] похоже на self.ws2

Тогда вам просто нужно передать ключевой аргумент" ws1 "или" ws2 "в write_data.

def write_data(self, data, title, key='ws1'):
    instance = vars(self)[key]
    lineCounter = vars(self)[key+"LineCount"]

    instance.write_row(lineCounter , 0, title)
    lineCounter += 1
    instance.write_row(lineCounter , 0, data)
    lineCounter += 1
...