Operadores booleanos en Python: and, or, not, precedencia y errores comunes
Python escribe los tres operadores básicos como palabras, and, or y not, los ordena en ese orden por debajo de los operadores de comparación, y devuelve un operando en lugar de un booleano puro desde and y or. El listado de abajo es la exportación a Python de la regla de entrada, generada por el propio motor.
| Lógica | Python | Nota |
|---|---|---|
NOT A | not a | Menor precedencia que las comparaciones: not a == b es not (a == b) |
A AND B | a and b | Cortocircuito; devuelve un operando |
A OR B | a or b | Cortocircuito; devuelve un operando |
A XOR B | a != b o a ^ b entre bools | ^ es bit a bit entre enteros |
A -> B | (not a) or b | No hay operador de implicación |
A <-> B | a == b entre bools | Igualdad de dos booleanos |
TRUE, FALSE | True, False | Con mayúscula; 1 y 0 son enteros, no aceptados por la exportación |
Las palabras son los operadores: a and b, a or b, not a. La precedencia es not, luego and, luego or, el mismo orden que esta referencia, con un giro que atrapa a la gente: las comparaciones ligan con más fuerza que not, así que not a == b es not (a == b). La página del error sobre precedencia entre lenguajes muestra el desliz; el analizador de aquí rechaza esa grafía directamente en lugar de adivinar.
and y or son de cortocircuito y devuelven uno de sus operandos, no necesariamente True o False: 0 or 5 es 5 y '' and 'x' es ''. Eso es cómodo y una trampa, porque un valor meramente «verdadero» (una lista no vacía, un número distinto de cero) no es el booleano True. El módulo exportado rechaza esos valores: su contrato de entrada exige que cada entrada sea exactamente True o False, y cualquier otra cosa, incluidos 0, 1 y None, lanza un InputError antes de evaluar.
Los operadores de un solo carácter pertenecen a los enteros: &, |, ^ y ~ son bit a bit. Sobre dos valores bool, &, | y ^ dan por casualidad booleanos (True ^ False es True), pero ~True es -2, y != entre booleanos es el o exclusivo. La exportación se genera de forma determinista a partir del modelo validado, una función por salida (output_allow_entry(inputs)) más una comprobación in_scope para los supuestos declarados, y su cabecera dice lo que no establece: que la regla sea completa, legal o segura.
Cómo leer la exportación
La cabecera del módulo registra las versiones del motor y de la semántica y dos resúmenes criptográficos, uno de la lógica y otro de los supuestos, para que quien revisa pueda saber qué revisión de la regla produjo el archivo. Las entradas se pasan como un diccionario con sus nombres declarados; las salidas son funciones de ese diccionario. Nada en el archivo lee la red, el sistema de archivos ni el reloj.
La regla de entrada, exportada por el motor
allow_entry := (member OR invited) AND NOT banned# -*- coding: utf-8 -*-
# Generated by Tangibool (tangibool.python/1). Do not edit by hand; regenerate from the source revision.
# Model: not stated
# Source revision: reference
# Interpretation status: not stated
"""Tangibool evaluator (decision model).
Generated deterministically from the validated Boolean model; it evaluates exactly that
model. It does not establish that the model is a complete, legal, or safe statement of a
real-world rule, and evaluating examples does not verify the rule.
Source revision: reference
Interpretation status: not stated
Exporter: 1.0.0 (format tangibool.python/1; engine 1.0.0; semantics tangibool-semantics/1)
Logic digest: f0daa82174670c788f59eb058d07f7601cd0ace4ed94d61a747cc26c41fd4e0d
Assumptions digest: d58ee1ad38e23e5093e4baa1047b5ae70d6972e08f555e34ac3fa16df63c4a78
Inputs (dict keys, declared order) and generated parameter names:
'member' -> input_member
'invited' -> input_invited
'banned' -> input_banned
Outputs (declared order) and their functions:
'allow_entry' -> output_allow_entry(inputs)
Assumptions (the declared scope, checked by in_scope(inputs)):
none; every complete assignment is in scope.
Input contract:
Every required input must be exactly True or False (type(value) is bool). Missing
inputs, None, strings, integers (including 0 and 1), and keys that are not declared
inputs raise InputError before anything is evaluated, including inputs that a
short-circuiting operator would never read. Results are always bool.
Scope:
Decision functions raise OutOfScopeError when the inputs violate an assumption; an
out-of-scope assignment is never turned into a False result. Pass check_scope=False
to evaluate without the scope check, and use in_scope(inputs) to test it separately.
Usage:
import tangibool_model as model
model.evaluate({'member': False, 'invited': False, 'banned': False})
# -> {'allow_entry': False}
model.output_allow_entry({'member': False, 'invited': False, 'banned': False})
# -> False
model.evaluate({'member': 1, 'invited': False, 'banned': False})
# raises InputError: 1 is an int, not a bool
"""
import collections.abc as _abc
from typing import Dict, Mapping, Tuple
__all__ = [
"MODEL_INFO",
"IDENTIFIER_MAP",
"INPUT_NAMES",
"OUTPUT_NAMES",
"ASSUMPTIONS",
"InputError",
"OutOfScopeError",
"minterm_index",
"in_scope",
"evaluate",
"output_allow_entry",
]
MODEL_INFO = {
"format": "tangibool.python/1",
"mode": "decision",
"model": None,
"revision": "reference",
"interpretation": None,
"exporter": "1.0.0",
"engine_version": "1.0.0",
"semantics_version": "tangibool-semantics/1",
"logic_digest": "f0daa82174670c788f59eb058d07f7601cd0ace4ed94d61a747cc26c41fd4e0d",
"assumptions_digest": "d58ee1ad38e23e5093e4baa1047b5ae70d6972e08f555e34ac3fa16df63c4a78",
"primary_output": "allow_entry",
"unused_inputs": (),
"subcircuits": (),
}
# Stable ID -> generated identifier (reversible mapping; names are exact, escaped strings).
IDENTIFIER_MAP = {
"v_79df34978043": {"kind": "input", "name": "member", "identifier": "input_member"},
"v_8afde06f51e3": {"kind": "input", "name": "invited", "identifier": "input_invited"},
"v_60b2536f5dc8": {"kind": "input", "name": "banned", "identifier": "input_banned"},
"f_ae8686d89791": {"kind": "output", "name": "allow_entry", "identifier": "output_allow_entry"},
}
INPUT_NAMES = ("member", "invited", "banned")
OUTPUT_NAMES = ("allow_entry",)
ASSUMPTIONS = ()
_DECLARED_INPUTS = frozenset(INPUT_NAMES)
_SCOPE_INPUTS = ()
_ASSUMPTION_FORMULAS = {entry["name"]: entry["formula"] for entry in ASSUMPTIONS}
class InputError(ValueError):
"""Raised when inputs are missing, undeclared, or not exactly True/False.
Every required input must satisfy type(value) is bool. Missing inputs, None, strings,
integers (including 0 and 1), and keys that are not declared inputs are rejected before
anything is evaluated. A missing input is never treated as False. The individual problems
are listed in the problems attribute.
"""
def __init__(self, problems):
self.problems = tuple(problems)
super().__init__("Invalid inputs: " + "; ".join(self.problems))
class OutOfScopeError(ValueError):
"""Raised when the inputs violate the model's assumptions (its declared scope).
Outside its assumptions the rule has no decision: this error is never a False result.
The names of the violated assumptions are in the violated attribute.
"""
def __init__(self, violated):
self.violated = tuple(violated)
details = ", ".join(name + " (" + _ASSUMPTION_FORMULAS.get(name, "?") + ")" for name in self.violated)
super().__init__(
"Out of scope: the inputs violate "
+ ("assumption " if len(self.violated) == 1 else "assumptions ")
+ details
+ ". The rule has no decision outside its assumptions; this is not a False result."
)
def _short_repr(value: object) -> str:
text = repr(value)
return text if len(text) <= 60 else text[:57] + "..."
def _checked_inputs(inputs: Mapping[str, bool], required: Tuple[str, ...], check_scope: bool) -> Dict[str, bool]:
"""Validate inputs strictly before anything is evaluated and return a plain copy."""
if type(check_scope) is not bool:
raise TypeError("check_scope must be True or False")
if not isinstance(inputs, _abc.Mapping):
raise InputError(["inputs must be a mapping from input names to True/False, got " + type(inputs).__name__])
problems = []
for key in inputs:
if type(key) is not str or key not in _DECLARED_INPUTS:
declared = ", ".join(repr(name) for name in INPUT_NAMES) or "none"
problems.append("undeclared input " + _short_repr(key) + " (declared inputs: " + declared + ")")
needed = tuple(required) + (_SCOPE_INPUTS if check_scope else ())
for name in needed:
if name not in inputs:
problems.append("missing required input " + repr(name))
for key, value in inputs.items():
if type(key) is str and key in _DECLARED_INPUTS and type(value) is not bool:
problems.append(
"input " + repr(key) + " must be True or False (type bool), got "
+ type(value).__name__ + " " + _short_repr(value)
)
if problems:
raise InputError(list(dict.fromkeys(problems)))
return dict(inputs.items())
def _require_bool_args(function: str, pairs: Tuple[Tuple[str, object], ...]) -> None:
problems = [
"argument " + repr(name) + " of " + function + " must be True or False (type bool), got "
+ type(value).__name__ + " " + _short_repr(value)
for name, value in pairs
if type(value) is not bool
]
if problems:
raise InputError(problems)
def minterm_index(*values: bool) -> int:
"""Row index of an assignment over a declared variable order.
The first value is the most significant bit, so all-False is row 0. Used for indexed
minterm (sum) and maxterm (product) forms.
"""
index = 0
for value in values:
if type(value) is not bool:
raise InputError(["minterm_index() takes True/False values, got " + type(value).__name__ + " " + _short_repr(value)])
index = index * 2 + (1 if value else 0)
return index
def _scope_values(values: Dict[str, bool]) -> Tuple[Tuple[str, bool], ...]:
"""Value of every enabled, confirmed assumption for validated inputs, in declared order."""
return ()
def _require_in_scope(values: Dict[str, bool]) -> None:
violated = tuple(name for name, holds in _scope_values(values) if not holds)
if violated:
raise OutOfScopeError(violated)
def in_scope(inputs: Mapping[str, bool]) -> bool:
"""True when the inputs satisfy every assumption (the model's declared scope).
Requires the inputs the assumptions read; raises InputError for invalid inputs.
"""
values = _checked_inputs(inputs, (), True)
return all(holds for _, holds in _scope_values(values))
# ---- Formula bodies (inputs are validated by the public functions below) ----
def _compute_output_allow_entry(input_member: bool, input_invited: bool, input_banned: bool) -> bool:
"""Decision output 'allow_entry': (member OR invited) AND NOT banned"""
return (input_member or input_invited) and (not input_banned)
# ---- Public API ----
def output_allow_entry(inputs: Mapping[str, bool], *, check_scope: bool = True) -> bool:
"""Decision output 'allow_entry' (stable ID f_ae8686d89791).
'allow_entry' := (member OR invited) AND NOT banned
Required inputs: 'member', 'invited', 'banned'.
Raises InputError for missing, undeclared, or non-bool inputs, and OutOfScopeError
when check_scope is True and the inputs violate an assumption.
"""
values = _checked_inputs(inputs, ("member", "invited", "banned"), check_scope)
if check_scope:
_require_in_scope(values)
output_allow_entry_value = _compute_output_allow_entry(values["member"], values["invited"], values["banned"])
return output_allow_entry_value
def evaluate(inputs: Mapping[str, bool], *, check_scope: bool = True) -> Dict[str, bool]:
"""Evaluate every output (declared order); each output is computed once.
Required inputs: 'member', 'invited', 'banned'.
Raises InputError for missing, undeclared, or non-bool inputs, and OutOfScopeError
when check_scope is True and the inputs violate an assumption.
"""
values = _checked_inputs(inputs, ("member", "invited", "banned"), check_scope)
if check_scope:
_require_in_scope(values)
output_allow_entry_value = _compute_output_allow_entry(values["member"], values["invited"], values["banned"])
return {
"allow_entry": output_allow_entry_value,
}
El error habitual
Escribir if flag == True: o pasar 1 como booleano. Las dos cosas se ejecutan en Python, y la segunda es exactamente lo que rechaza el contrato de entrada de la exportación, porque la regla se escribió sobre dos valores, no sobre enteros.
Preguntas
¿La exportación ejecuta la regla o la verifica?
Evalúa el modelo validado y nada más. Su propia documentación dice que evaluar ejemplos no verifica la regla; las comprobaciones de este sitio y de la app son las que establecen propiedades de la regla.
¿Por qué no hay operador de implicación?
Python no tiene ninguno. A -> B se convierte en (not a) or b, que es la ley de eliminación de la implicación; la exportación la aplica por ti.
Relacionado
Véase también
- La precedencia cambia entre lenguajes: not a == b en Python
- ^ significa XOR en C, Java y Python, no AND ni potencia
- != entre booleanos es XOR
- El doble igual (==) compara valores; para equivalencia lógica usa ↔
- De expresión booleana a Python, SQL, SMT-LIB y LaTeX
- Eliminación de la implicación: A → B = A' + B
- Operadores lógicos en JavaScript: &&, ||, !, truthiness y precedencia
- Lógica booleana en SQL: AND, OR, NOT y la trampa de NULL (lógica trivaluada)
Lenguajes
Generado a partir del motor de Tangibool, semántica tangibool-semantics/1, motor 1.0.0, compilación . Cada tabla, mapa, simplificación y veredicto de estas páginas lo calculó el motor de Tangibool al compilar el sitio, y cada afirmación la volvió a comprobar el mismo verificador exacto que usa la app. Los límites se indican donde aplican. © 2026 Foreranger LTD.