Pět. Tři. Neboli jednoduché počty

12. 10. 2012 18:55 (aktualizováno) Petr Blahoš

SQLAlchemy je nekonečný zdroj inspirace. Několikrát jsem si řekl: Jak to asi dělají. A protože je to Python, tak jsem za okamžik věděl. Buď jsem na to kápnul sám (Wu-Shiho kleště), nebo jsem se podíval do kódu. O co se s vámi podělím dnes?

Nadefinujete si tabulku, třeba takhle:

person = Table("person", metadata,
    Column("id", Integer()),
    Column("name", Unicode()),
    Column("address", Unicode()),
    Column("sex", Integer()),
    Column("regtm", DATETIME()),
)

A pak sestavíte dotaz:

q = person.select().where(
    person.c.name=="John Smith"
    and
    person.c.regt>datetime.datetime(2012, 1, 1)
)

Mě se moc líbila konstrukce té where clause, tak jsem si řekl, jak to asi dělají? Je to samozřejmně banální. V Pythonu lze pro objekt nadefinovat význam operátorů. SQLAlchemy pro objekt Column definuje porovnání, and, a další. Výsledkem těchto operátorů je pak objekt, který dokáže vygenerovat kus SQL.

Ukážeme si jednoduchý příklad, na stejném principu, ale pro symbolickou aritmetiku, a s těmi nejjednoduššími operacemi. Začneme výrazem, nad kterým nadefinujeme sčítání, odčítání, násobení a dělení.

class Expression(object):
    def __add__(self, rt):
        return Plus(self, rt)
    def __sub__(self, rt):
        return Minus(self, rt)
    def __mul__(self, rt):
        return Multiply(self, rt)
    def __div__(self, rt):
        return Divide(self, rt)

class BinaryOperation(Expression):
    def __init__(self, lt, rt):
        self.lt = lt
        self.rt = rt
    def __str__(self):
        return "(%s %s %s)" % (self.lt, self.__class__.OPERATOR, self.rt)

class Plus(BinaryOperation):
    OPERATOR = "+"

class Minus(BinaryOperation):
    OPERATOR = "-"

class Multiply(BinaryOperation):
    OPERATOR = "*"

class Divide(BinaryOperation):
    OPERATOR = "/"

Nechci vysvětlovat, co dělá která funkce. To si najdete v dokumentaci, a vyzkoušíte. Teď přidáme symboly:

class Primary(Expression):
    pass

class Symbol(Primary):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return self.name

No, a teď už nám bude fungovat Symbol(„a“)*Symbol(„b“). Zkuste si tohle:

print Symbol("a")+Symbol("b")*Symbol("e")-Symbol("c")/Symbol("d")
print (Symbol("a")+Symbol("b"))*Symbol("e")-Symbol("c")/Symbol("d")
print (Symbol("a")+Symbol("b")*Symbol("e")-Symbol("c"))/Symbol("d")

Celé to najdete tady.

Ano, ano. Python předpokládá, že plus je plus a krát je krát, takže fungují priority, a fungují také závorky. Chcete si naprogramovat vlastní systém na symbolickou matematiku? Jo. Nedělejte to. Použijte http://scipy.org/. Nebo http://sympy.org/.
Já osobně si myslím, že na ukázku to stačí, ale jestli to téma chcete rozebrat víc, napište komentář. Co tak? Proč funguje Symbol(“a”)*3, ale nefunguje 3*Symbol(“a”), jak udělat ohodnocení, nic dalšího mě teď nenapadá.

Sdílet