Artigo
· Set. 1, 2023 4min de leitura

Desafios das Tuplas

Visão geral

Com o cross-skilling do objectScript do IRIS para o Python, ficam claras algumas diferenças fascinantes na sintaxe.

Uma dessas áreas é como o Python retorna Tuplas de um método com desempacotamento automático.

Efetivamente, isso se apresenta como um método que retorna vários valores. Que invenção incrível :)

out1, out2 = some_function(in1, in2)

O ObjectScript tem uma abordagem diferente com o ByRef e os parâmetros de saída.

Do ##class(some_class).SomeMethod(.inAndOut1, in2, .out2)

Onde:

  • inAndOut1 é o ByRef
  • out2 é a saída

O ponto à esquerda (".") na frente do nome da variável passa o ByRef e a saída.

A finalidade deste artigo é descrever como a comunidade do utilitário PyHelper foi otimizada para oferecer uma maneira pythônica de aproveitar o ByRef e os parâmetros de saída. Ele dá acesso a %objlasterror e tem uma abordagem para lidar com o tipo None do Python.
 

ByRef de exemplo

A invocação normal para o embedded python seria:

oHL7=iris.cls("EnsLib.HL7.Message")._OpenId('er12345')

Quando a abertura desse método falha, a variável "oHL7" é uma string vazia.
Na assinatura desse método, há um parâmetro de status disponível para o object script que fornece uma explicação do problema exato.
Por exemplo:

  • O registro pode não existir
  • Não foi possível abrir o registro no modo de simultaneidade exclusiva padrão ("1"), dentro do tempo limite
ClassMethod %OpenId(id As %String = "", concurrency As %Integer = -1, ByRef sc As %Status = {$$$OK}) As %ObjectHandle

O método TupleOut pode ajudar no retorno do valor do argumento sc, de volta a um contexto python.
 

> oHL7,tsc=iris.cls("alwo.PyHelper").TupleOut("EnsLib.HL7.Message","%OpenId",['sc'],1,'er145999', 0)
> oHL7
''
> iris.cls("%SYSTEM.Status").DisplayError(tsc)
ERROR #5809: Object to Load not found, class 'EnsLib.HL7.Message', ID 'er145999'1
```

A lista ['sc'] contém um único item nesse caso. Ela pode retornar vários valores Byref, e na ordem especificada. O que é útil para descompactar automaticamente as variáveis pretendidas do Python.

Exemplo de como lidar com um parâmetro de saída

Código em Python:

> oHL7=iris.cls("EnsLib.HL7.Message")._OpenId('145')
> oHL7.GetValueAt('<%MSH:9.1')
''

A string retornada está vazia, mas isso se deve ao elemento realmente estar vazio OU algo que deu errado.
No object script, há também um parâmetro de status de saída (pStatus) que pode ser acessado para determinar essa condição.

Código em object script:

> write oHL7.GetValueAt("<%MSH:9.1",,.pStatus)
''
> Do $System.Status.DisplayError(pStatus)
ERROR <Ens>ErrGeneral: No segment found at path '<%MSH'

Com TupleOut, a funcionalidade equivalente pode ser obtida ao retornar e descompactar ambos o valor de retorno do método E o parâmetro de saída do status.

Código em Python:

> hl7=iris.cls("EnsLib.HL7.Message")._OpenId(145,0)
> val, status = iris.cls("alwo.PyHelper").TupleOut(hl7,"GetValueAt",['pStatus'],1,"<&$BadMSH:9.1")
> val==''
True
> iris.cls("%SYSTEM.Status").IsError(status)
1
> iris.cls("%SYSTEM.Status").DisplayError(status)
ERROR <Ens>ErrGeneral: No segment found at path '<&$BadMSH'1

Variável especial %objlasterror

No objectscript, há acesso a variáveis de porcentagem no escopo do método.
Há cenários em que detectar ou acessar a variável especial %objlasterror é útil após chamar uma API de terceiros ou CORE
O método TupleOut permite o acesso a %objlasterror, como se tivesse sido definido como um parâmetro de saída, ao invocar métodos do Python

> del _objlasterror

> out,_objlasterror=iris.cls("alwo.PyHelper").TupleOut("EnsLib.HL7.Message","%OpenId",['%objlasterror'],1,'er145999', 0) 

> iris.cls("%SYSTEM.Status").DisplayError(_objlasterror)
ERROR #5809: Object to Load not found, class 'EnsLib.HL7.Message', ID 'er145999'1

Quando None não é uma String

O TupleOut lida com as referências a None do Python como objectscript indefinido. Isso permite que os parâmetros sejam padronizados e os métodos se comportem de forma consistente.
Isso é importante, por exemplo, com %Persistent::%OnNew, em que o método %OnNew não é acionado quando None é fornecido para initvalue, mas seria acionado se uma string vazia fosse fornecida.

No objectscript, a implementação pode dizer:

do oHL7.myMethod("val1",,,"val2")

Observe a ausência de variáveis entre vírgulas.

O TupleOut facilita o mesmo comportamento com:

Python:

iris.cls("alwo.PyHelper").TupleOut(oHL7,"myMethod",[],0,"val1",None,None,"val2")

Outra maneira de considerar isso é poder ter uma implementação de uma linha de código de invocação, com um comportamento flexível dependendo da pré-configuração das variáveis:

Object Script:

set arg1="val1"
kill arg2
kill arg3
set arg4="val2"
do oHL7.myMethod(.arg1, .arg2, .arg3, .arg4)

O TupleOut facilita o mesmo comportamento com:

Python:

arg1="val1"
arg2=None
arg3=None
arg4="val2"
iris.cls("alwo.PyHelper").TupleOut(oHL7,"myMethod",[],0,arg1,arg2,arg3,arg4)

Lista e dicionários

Ao lidar com parâmetros para entrada, ByRef e saída, o TupleOut utiliza o mapeamento automático do PyHelper entre:
Listas do IRIS e do Python
Arrays do IRIS e do Python
Onde é preciso sempre usar strings para representar as chaves do dicionário ao passar de Arrays do IRIS para tipos Dict do Python.

Conclusão

Espero que este artigo ajude a inspirar novas ideias, discussões e sugestões sobre o Embedded Python.

Também espero que incentive a explorar a flexibilidade do IRIS em se adaptar facilmente para enfrentar novos desafios.

Discussão (0)1
Entre ou crie uma conta para continuar