python - guia - mpu6050 arduino mega
Lea el valor de celda de Excel y no la fórmula que lo computa-openpyxl (4)
Estoy usando openpyxl para leer el valor de la celda (excel addin-webservice actualice esta columna).
He usado
data_only = True
pero no muestra el valor actual de la celda, sino el valor almacenado la última vez que Excel leyó la hoja.
wbFile = openpyxl.load_workbook(filename = xxxx,data_only=True)
wsFile = wbFile[c_sSheet]
¿Como puedo leer el valor real de la celda?
Como @Charlie Clark mencionó, podría usar
xlwings
(si tiene MS Excel).
Aquí un ejemplo
digamos que tiene una hoja de Excel con fórmulas, por ejemplo, defino una con
openpyxl
from openpyxl import Workbook, load_workbook
wb=Workbook()
ws1=wb[''Sheet'']
ws1[''A1'']=''a''
ws1[''A2'']=''b''
ws1[''A3'']=''c''
ws1[''B1'']=1
ws1[''B2'']=2
ws1[''B3'']=''=B1+B2''
wb.save(''to_erase.xlsx'')
Como se mencionó, si volvemos a cargar Excel con
openpyxl
, no obtendremos la fórmula evaluada
wb2 = load_workbook(filename=''to_erase.xlsx'',data_only=True)
wb2[''Sheet''][''B3''].value
puede usar
xlwings
para obtener la fórmula evaluada por excel:
import xlwings as xw
wbxl=xw.Book(''to_erase.xlsx'')
wbxl.sheets[''Sheet''].range(''B3'').value
que devuelve 3, el valor esperado.
Lo encontré bastante útil al trabajar con hojas de cálculo con fórmulas muy complicadas y referencias entre hojas.
Como dice @ alex-martelli, openpyxl no evalúa las fórmulas. Cuando abre un archivo de Excel con openpyxl, tiene la opción de leer las fórmulas o el último valor calculado. Si, como indica, la fórmula depende de complementos, el valor almacenado en caché nunca puede ser exacto. Como complementos fuera de la especificación del archivo, nunca serán compatibles. En su lugar, es posible que desee ver algo como xlwings.org que puede interactuar con el tiempo de ejecución de Excel.
Enfrenté el mismo problema. Necesario para leer los valores de las celdas, sean cuales sean esas celdas: escalares, fórmulas con valores calculados previamente o fórmulas sin ellos, prefiriéndose la tolerancia a fallos sobre la corrección.
La estrategia es bastante sencilla:
- si una celda no contiene fórmula, devuelve el valor de la celda;
- si es una fórmula, intente obtener su valor precalculado;
-
si no puede, intente evaluarlo usando
pycel
; -
si falla (debido al soporte limitado de fórmulas de
pycel
o con algún error), advierta y devuelva Ninguno.
Hice una clase que oculta toda esta maquinaria y proporciona una interfaz simple para leer los valores de las celdas.
Es fácil modificar la clase para que genere una excepción en el paso 4, si se prefiere la corrección sobre la tolerancia a fallas.
Espero que ayude a alguien.
from traceback import format_exc
from pathlib import Path
from openpyxl import load_workbook
from pycel.excelcompiler import ExcelCompiler
import logging
class MESSAGES:
CANT_EVALUATE_CELL = ("Couldn''t evaluate cell {address}."
" Try to load and save xlsx file.")
class XLSXReader:
"""
Provides (almost) universal interface to read xlsx file cell values.
For formulae, tries to get their precomputed values or, if none,
to evaluate them.
"""
# Interface.
def __init__(self, path: Path):
self.__path = path
self.__book = load_workbook(self.__path, data_only=False)
def get_cell_value(self, address: str, sheet: str = None):
# If no sheet given, work with active one.
if sheet is None:
sheet = self.__book.active.title
# If cell doesn''t contain a formula, return cell value.
if not self.__cell_contains_formula(address, sheet):
return self.__get_as_is(address, sheet)
# If cell contains formula:
# If there''s precomputed value of the cell, return it.
precomputed_value = self.__get_precomputed(address, sheet)
if precomputed_value is not None:
return precomputed_value
# If not, try to compute its value from the formula and return it.
# If failed, report an error and return empty value.
try:
computed_value = self.__compute(address, sheet)
except:
logging.warning(MESSAGES.CANT_EVALUATE_CELL
.format(address=address))
logging.debug(format_exc())
return None
return computed_value
# Private part.
def __cell_contains_formula(self, address, sheet):
cell = self.__book[sheet][address]
return cell.data_type is cell.TYPE_FORMULA
def __get_as_is(self, address, sheet):
# Return cell value.
return self.__book[sheet][address].value
def __get_precomputed(self, address, sheet):
# If the sheet is not loaded yet, load it.
if not hasattr(self, ''__book_with_precomputed_values''):
self.__book_with_precomputed_values = load_workbook(
self.__path, data_only=True)
# Return precomputed value.
return self.__book_with_precomputed_values[sheet][address].value
def __compute(self, address, sheet):
# If the computation engine is not created yet, create it.
if not hasattr(self, ''__formulae_calculator''):
self.__formulae_calculator = ExcelCompiler(self.__path)
# Compute cell value.
computation_graph = self.__formulae_calculator.gen_graph(
address, sheet=sheet)
return computation_graph.evaluate(f"{sheet}!{address}")
wb = openpyxl.load_workbook(filename, data_only=True)
La bandera
data_only
ayuda.