新しい投稿

検索

ダイジェスト
· 9 hr 前

InterSystems Developers Publications, Week February 02 - 08, 2026, Digest

Articles
Announcements
Questions
Discussions
February 02 - 08, 2026Week at a GlanceInterSystems Developer Community
ダイジェスト
· 10 hr 前
ダイジェスト
· 11 hr 前

Publications des développeurs d'InterSystems, semaine Février 02 - 08, 2026, Résumé

Février 02 - 08, 2026Week at a GlanceInterSystems Developer Community
記事
· 12 hr 前 3m read

Parámetros Variádicos en ObjectScript: La Solución Elegante que No Sabías que Existía

¿Qué son los parámetros variádicos?

ObjectScript permite definir métodos que aceptan un número variable de argumentos usando la sintaxis `args...`. En lugar de fijar cuántos parámetros recibe un método, dejas que el llamante decida cuántos enviar.

Se pueden invocar de dos formas:

1. Con argumentos individuales: `metodo(val1, val2, val3)`

2. Expandiendo un array: `metodo(args...)`

 
 

Crea tus propios métodos variádicos

Puedes definir un método con un parámetro fijo y un número variable de extras:

ClassMethod MiMetodo(fijo As %String, extras...) As %Status
{
    Write "Parámetro fijo: ", fijo, !
    Write "Número de extras: ", $Get(extras, 0), !

    For i = 1:1:$Get(extras, 0) {
        Write "  Extra ", i, ": ", extras(i), !
    }
    Quit $$$OK
}

Y llamarlo de cualquiera de estas dos formas:

// Forma 1: Argumentos individuales
Do ##class(MiClase).MiMetodo("hola", "valor1", "valor2")

// Forma 2: Expandiendo un array
Set params = 2
Set params(1) = "valor1"
Set params(2) = "valor2"
Do ##class(MiClase).MiMetodo("hola", params...)

// Ambas producen la misma salida:
//   Parámetro fijo: hola
//   Número de extras: 2
//   Extra 1: valor1
//   Extra 2: valor2

 

La convención del array

El array que se pasa con `args...` sigue una convención simple de ObjectScript:

- `args` contiene el número de elementos

- `args(1)`, `args(2)`, etc. contienen los valores

 

Esto significa que estas dos llamadas son equivalentes:

// Forma 1: Argumentos individuales
Set result = statement.%Execute("Juan", 25, "Barcelona")

// Forma 2: Expandiendo un array
Set args = 3
Set args(1) = "Juan"
Set args(2) = 25
Set args(3) = "Barcelona"
Set result = statement.%Execute(args...)

 

La segunda forma es la que nos interesa: podemos construir el array dinámicamente y expandirlo en la llamada.

 

Aplicación práctica: SQL dinámico seguro

Construir consultas SQL dinámicas concatenando strings es tentador... y peligroso:

// ⚠️ NO HAGAS ESTO - Vulnerable a SQL Injection
Set sql = "SELECT * FROM Paciente WHERE Nombre LIKE '%" _ nombre _ "%'"

 

La forma correcta es usar `%SQL.Statement` con parámetros `?`. Pero, ¿qué pasa cuando no sabes cuántos parámetros tendrás hasta el momento de ejecución?

Aquí es donde los variádicos brillan. El método `%Execute()` está definido así:

Method %Execute(%parm...) As %SQL.StatementResult

Acepta parámetros variádicos, así que podemos construir nuestro array dinámicamente y expandirlo:

 

Implementación completa

ClassMethod BuscarPacientes(filtrosJSON As %DynamicObject) As %SQL.StatementResult
{
    Set sql = "SELECT ID, Nombre, Edad, Ciudad FROM Paciente WHERE 1=1"
    // Construir condiciones y argumentos dinámicamente
    Set args = 0  // args será nuestro array variádico
    Set iterator = filtrosJSON.%GetIterator()
    While iterator.%GetNext(.key, .value) {
        If key = "nombre" {
            Set sql = sql _ " AND Nombre LIKE ?"
            Set args($Increment(args)) = "%" _ value _ "%"
        } ElseIf key = "edad" {
            Set sql = sql _ " AND Edad = ?"
            Set args($Increment(args)) = value
        } ElseIf key = "ciudad" {
            Set sql = sql _ " AND Ciudad = ?"
            Set args($Increment(args)) = value
        }
    }

    // Preparar el statement
    Set statement = ##class(%SQL.Statement).%New()
    Set status = statement.%Prepare(sql)
    If $$$ISERR(status) { Quit $$$NULLOREF }

    // ¡La magia! Expandir el array como argumentos variádicos
    Quit statement.%Execute(args...)
}

 

Ejemplo de uso

// Filtros dinámicos desde un JSON
Set filtros = {"nombre": "Juan", "ciudad": "Barcelona"}

Set resultado = ##class(MiPaquete.Utilidades).BuscarPacientes(filtros)

While resultado.%Next() {
    Write resultado.%Get("Nombre"), " - ", resultado.%Get("Ciudad"), !
}

No importa si recibes 1, 5 o 20 filtros: el mismo código los maneja de forma segura.

 

Conclusión

Los parámetros variádicos con `args...` te permiten:

- Construir arrays de argumentos dinámicamente

- Expandirlos al llamar cualquier método que los soporte

- Evitar SQL injection usando parámetros preparados

- Eliminar cadenas interminables de `If`/`ElseIf`

 

Referencias

Variable number of method arguments

Passing a variable number of arguments

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください
記事
· 13 hr 前 4m read

Usando Auditoria Python para depuração de Embedded Python

A PEP 578 adicionou hooks de auditoria ao Python. Uma grande variedade de eventos (carregamento de módulos, interações com o sistema operacional e assim por diante) aciona eventos de auditoria aos quais você pode se inscrever.

Veja como fazer isso. Primeiro, crie um hook de Python embutido (embedded python hook):

Class User.Python {

/// do ##class(User.Python).Audit() 
ClassMethod Audit() [ Language = python ] 
{ 
    import sys 
    import time
    
    def logger(event,args):      
        if event=='import':         
        module = args[0]         
        print(f"Carregando {module}")         
        if module == "numpy":             
            print(f"Módulo {module} proibido. Encerrando processo em 3.")             
            time.sleep(3)             
            sys.exit(0)      
        elif event in ('compile','exec'):         
            print(f"{event}: {args}")      
        elif event in ('code.new','open'):         
            # não faz nada para este evento         
            x=1      
        else:         
            print(f"{event}")

sys.addaudithook(logger) }

}

Neste exemplo, nós:

  • Encerramos o processo se o numpy começar a ser carregado
  • Exibimos o evento e os argumentos para eventos compile/exec
  • Ignoramos eventos de code
  • Registramos todos os outros eventos

Tudo isso será gravado no STDOUT padrão.

Para começar a auditar, basta chamar este método para registrar seu hook, ou você pode até mesmo fazer isso automaticamente no início do job:

%ZSTART 
JOB     
    new $namespace     
    set $namespace = "%SYS"     
    do ##class(User.Python).Audit()     
    quit 
LOGIN     
    do JOB     
    quit

Aqui está um exemplo de saída:

%SYS>:PY
Loading code
exec: (<code object <module> at 0x000001AB82A0F2F0, file "c:\intersystems\iris\lib\python\lib\code.py", line 1>,)
Loading traceback
exec: (<code object <module> at 0x000001AB82A173A0, file "c:\intersystems\iris\lib\python\lib\traceback.py", line 1>,)
Loading linecache
exec: (<code object <module> at 0x000001AB82A17A80, file "c:\intersystems\iris\lib\python\lib\linecache.py", line 1>,)
Loading tokenize
exec: (<code object <module> at 0x000001AB82A32030, file "c:\intersystems\iris\lib\python\lib\tokenize.py", line 1>,)
Loading token
exec: (<code object <module> at 0x000001AB82A323A0, file "c:\intersystems\iris\lib\python\lib\token.py", line 1>,)
compile: (b'lambda _cls, type, string, start, end, line: _tuple_new(_cls, (type, string, start, end, line))', '<string>')
exec: (<code object <module> at 0x000001AB82A32710, file "<string>", line 1>,)
sys._getframe
object.__setattr__
Loading codeop
exec: (<code object <module> at 0x000001AB82A32EA0, file "c:\intersystems\iris\lib\python\lib\codeop.py", line 1>,)
Loading __future__
exec: (<code object <module> at 0x000001AB82A472F0, file "c:\intersystems\iris\lib\python\lib\__future__.py", line 1>,)
 
Python 3.9.5 (default, May 31 2022, 12:35:47) [MSC v.1927 64 bit (AMD64)] on win32
Type quit() or Ctrl-D to exit this shell.
compile: (b'import iris', '<input>')
compile: (b'import iris\n', '<input>')
compile: (b'import iris\n\n', '<input>')
exec: (<code object <module> at 0x000001AB82A60870, file "<input>", line 1>,)
>>> import json
compile: (b'import json', '<input>')
compile: (b'import json\n', '<input>')
compile: (b'import json\n\n', '<input>')
exec: (<code object <module> at 0x000001AB82A60870, file "<input>", line 1>,)
Loading json
exec: (<code object <module> at 0x000001AB82A60DF0, file "c:\intersystems\iris\lib\python\lib\json\__init__.py", line 1>,)
Loading json.decoder
os.listdir
exec: (<code object <module> at 0x000001AB82A67710, file "c:\intersystems\iris\lib\python\lib\json\decoder.py", line 1>,)
Loading json.scanner
exec: (<code object <module> at 0x000001AB82A679D0, file "c:\intersystems\iris\lib\python\lib\json\scanner.py", line 1>,)
Loading _json
Loading json.encoder
exec: (<code object <module> at 0x000001AB82A71500, file "c:\intersystems\iris\lib\python\lib\json\encoder.py", line 1>,)
>>> x=1
compile: (b'x=1', '<input>')
compile: (b'x=1\n', '<input>')
compile: (b'x=1\n\n', '<input>')
exec: (<code object <module> at 0x000001AB82A60870, file "<input>", line 1>,)

Acho que isso pode ser muito útil para depuração.

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください