0

I would like to call a function with another function as argument, which is not yet defined and callable. Is there a pythonic way how to do this?

I know that you can give a function as an argument for another function, like this answer suggests:

Python function as a function argument?

But this somehow is not possible for functions which are not yet defined and callable.

I wrote a lot of those repetitive code recently and I'm pretty sure there must be a more pythonic way to do this.

Repetitive code:

import pymysql

def database_connection():
    return pymysql.connect(db="MyDatabase", user='root', host="127.0.0.1", password="SecretPassword")

def mysql_request_true(sql_text):
    connection = database_connection()
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql_text)
            result = True
        connection.commit()
        return result
    except ConnectionError:
        return False
    finally:
        connection.close()


def mysql_request_database_id(sql_text):
    connection = database_connection()
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql_text)
            result = cursor.lastrowid
        connection.commit()
        return result
    except ConnectionError:
        return False
    finally:
        connection.close()


def mysql_request_fetchone(sql_text):
    connection = database_connection()
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql_text)
            result = cursor.fetchone()
        connection.commit()
        return result
    except ConnectionError:
        return False
    finally:
        connection.close()


def mysql_request_fetchall(sql_text):
    connection = database_connection()
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql_text)
            result = cursor.fetchall()
        connection.commit()
        return result
    except ConnectionError:
        return False
    finally:
        connection.close()

What I try to achieve:

import pymysql

def database_connection():
    return pymysql.connect(db="MyDatabase", user='root', host="127.0.0.1", password="SecretPassword")

def mysql_request(sql_text, cmd):
    connection = database_connection()
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql_text)
            result = cmd
        connection.commit()
        return result
    except ConnectionError:
        return False
    finally:
        connection.close()

def mysql_request_true(sql_text):
    return mysql_request(sql_text, True)

def mysql_request_database_id(sql_text):
    return mysql_request(sql_text, cmd=cursor.lastrowid)

def mysql_request_fetchone(sql_text):
    return mysql_request(sql_text, cmd=cursor.fetchone())

def mysql_request_fetchall(sql_text):
    return mysql_request(sql_text, cmd=cursor.fetchall())

The code sample above does not work, because cursor is not yet defined when I give it as an argument.

Does anybody know how to do this? Thank you very much for your answers.

Yannick
  • 337
  • 3
  • 13
  • One way to do it would be to have a dictionary with the keys being strings and the values being functions. Then you pass the command as a string and find the corresponding function to call in the dictionary. – Calvin Godfrey Jun 21 '19 at 14:52

3 Answers3

2

So I think the issue you might have is that you need a cursor for each function, but do not want to repeat the call to create a cursor each time. One way to counteract this would be a wrapper function which provided a cursor:

from functools import wraps


def with_cursor(func):
    @wraps(func)
    def decorator_function(self, *args, **kwargs):
        cursor = connection.cursor()
        context = func(self, cursor, *args, **kwargs)
        cursor.close()
        return context

    return decorator_function

In this way, each function takes cursor as the first argument, but can then be sure it is available.

pypalms
  • 461
  • 4
  • 12
1

You can defer resolving the function's name with simple lambda:

def my_func(param, cmd=lambda: this_is_not_yet_defined_fn):
    print(cmd()(param))

this_is_not_yet_defined_fn = sum

my_func([1, 2])

Prints:

3
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
1

I think you can get the desired behavior using lambda. Just pass a function extracting the desired feature of cursor as an argument to you mysql_request function as such:

def mysql_request(sql_text, cmd):
    connection = database_connection()
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql_text)
            result = cmd(cursor) # Call cmd which extracts the desired information
        connection.commit()
        return result
    except ConnectionError:
        return False
    finally:
        connection.close()

Then you can pass the cmd argument as a lambda function:

def mysql_request_true(sql_text):
    return mysql_request(sql_text, lambda cursor:True)

def mysql_request_database_id(sql_text):
    return mysql_request(sql_text, lambda cursor:cursor.lastrowid)

def mysql_request_fetchone(sql_text):
    return mysql_request(sql_text, lambda cursor:cursor.fetchone())

def mysql_request_fetchall(sql_text):
    return mysql_request(sql_text, lambda cursor:cursor.fetchall())
pascscha
  • 1,623
  • 10
  • 16