Python中的软件设计。我应该使用一个模块还是单独使用?

时间:2015-02-11 07:13:00

标签: python mysql architecture

我用Python编写了两个脚本:

第一个将列表的关键值附加到列表中。

第二个使用该列表在MySQL数据库上创建列。

最初我在同一个模块中写了它们。但是,如果我将它们分成两个不同的模块或将它们放在一起会更好吗?

如果它能更好地分离它们,那么在另一个文件中使用列表的pythonic方法是什么?我知道不建议导入变量。

以下是代码:

import pymysql

# This script first extract dictionary key values. Then, it creates columns using the keys values from the dictionaries.

# login into mysql
conn = pymysql.connect("localhost", "*****", "******", "tutorial")

# creating a cursor object
c = conn.cursor()

# update here table from mysql
table_name = "table01"

# data
dicts = {'id': 5141, 'product_id': 193, 'price_ex_tax': 90.0000, 'wrapping_cost_tax': 0.0000, 'type': 'physical', 'ebay_item_id': 444, 'option_set_id': 38, 'total_inc_tax': 198.0000, 'quantity': 2, 'price_inc_tax': 99.0000, 'cost_price_ex_tax': 0.0000, 'name': 'UQ Bachelor Graduation Gown Set', 'configurable_fields': [], 'base_cost_price': 0.0000, 'fixed_shipping_cost': 0.0000, 'wrapping_message': '', 'order_address_id': 964, 'total_ex_tax': 180.0000, 'refund_amount': 0.0000, 'event_name': None, 'cost_price_inc_tax': 0.0000, 'cost_price_tax': 0.0000, 'wrapping_cost_inc_tax': 0.0000, 'wrapping_name': '', 'price_tax': 9.0000, 'is_bundled_product ': False, 'ebay_transaction_id': 4444, 'bin_picking_number': 4444, 'parent_order_product_id': None, 'event_date': '', 'total_tax': 18.0000, 'wrapping_cost_ex_tax': 0.0000, 'base_total': 198.0000, 'product_options': [{'id': 4208, 'display_name': 'Gown size (based on height)', 'name': 'Bachelor gown size', 'display_value': 'L (175-182cm)', 'display_style': 'Pick list', 'type': 'Product list', 'option_id': 19, 'value': 77, 'product_option_id': 175, 'order_product_id': 5141}, {'id': 4209, 'display_name': 'Hood', 'name': 'H-QLD-BAC-STD', 'display_value': 'UQ Bachelor Hood', 'display_style': 'Pick list', 'type': 'Product list', 'option_id': 42, 'value': 119, 'product_option_id': 176, 'order_product_id': 5141}, {'id': 4210, 'display_name': 'Trencher size (based on head circumference)', 'name': 'Trencher size', 'display_value': 'M (53-54cm)', 'display_style': 'Pick list', 'type': 'Product list', 'option_id': 20, 'value': 81, 'product_option_id': 177, 'order_product_id': 5141}], 'base_price': 99.0000, 'sku': 'S-QLD-BAC-STD', 'return_id': 0, 'applied_discounts': [{'id': 'coupon', 'amount': 30}], 'quantity_shipped': 0, 'base_wrapping_cost': 0.0000, 'is_refunded': False, 'weight': 2.0000, 'order_id': 615496}  # noqa

# creating empty lists
int_keys_lists = []
str_keys_lists = []
list_keys_lists = []


def extractDictKeys():

    # for loop that runs through the dictionary, extracting the keys when their valures are int or str, and appending to the corresponding list
    for i, j in enumerate(dicts):
        k, v = list(dicts.items())[i]
        if type(dicts[j]) != str:
            int_keys_lists.append(k)
        else:
            str_keys_lists.append(k)


def createColumnStrKeys():
    # for loop that create a column for each str key on the list
    for i, j in enumerate(str_keys_lists):
        c.execute("ALTER TABLE {0} ADD COLUMN {1} VARCHAR(255)".format(table_name, str_keys_lists[i]))
        conn.commit()


def createColumnIntKeys():
    # for loop that create a column for each id or float key on the list
    for i, j in enumerate(int_keys_lists):
        c.execute("ALTER TABLE {0} ADD COLUMN {1} int(30)".format(table_name, int_keys_lists[i]))
        conn.commit()

extractDictKeys()
createColumnStrKeys()
createColumnIntKeys()

2 个答案:

答案 0 :(得分:0)

您的设计存在一些问题。

函数不应该使用全局变量。函数接收变量作为参数,然后返回一个值(在某些情况下值为void

例如:

def extract_dict_keys(dictionary):
    key_list = list()
    int_key_list = list()
    str_key_list = list()
    # Your code here
    ..........
    return key_list, int_key_list, str_key_list

def create_col__str_keys(conn, dictionary, key_list):
    cursor = conn.cursor()
    # Your code here
    ..........
    # Commit outside of the loop
    conn.commit() # Though it's usually not recommended to commit in the function

def create_col__int_keys(conn, dictionary, key_list):
    cursor = conn.cursor()
    # Your code here
    ..........
    conn.commit()

只有在您使所有代码彼此独立之后,才能将它们组织成模块

如何将代码构建到模块中取决于代码可重用的程度,以及它们如何相互关联。例如,我将所有全局变量放入一个将要执行的主文件,将实用程序函数放入另一个模块,将sql相关的函数放入另一个模块中:

main.py

from utilities import extract_dict_keys
from sql import create_col_str_keys, create_col_int_keys

# login into mysql
conn = pymysql.connect("localhost", "*****", "******", "tutorial")

# data
data = {...}  # noqa
keys, int_keys, str_keys = extract_dict_keys(data)
create_col_int_keys(conn, data, int_keys)
create_col_str_keys(conn, data, str_keys)

utilities.py

def extract_dict_keys(dictionary):
    key_list = list()
    int_key_list = list()
    str_key_list = list()
    # Your code here
    ..........
    return key_list, int_key_list, str_key_list

sql.py

import pymysql

def create_col__str_keys(conn, dictionary, key_list):
    cursor = conn.cursor()
    # Your code here
    ..........
    conn.commit()

def create_col__int_keys(conn, dictionary, key_list):
    cursor = conn.cursor()
    # Your code here
    ..........
    conn.commit()

此外,关于SQL注入漏洞,您不应使用cursor.execute(a_built_string)

考虑这种情况:

cursor.execute("DELETE FROM users WHERE id = {uid}".format(uid=user_id))

有人聪明地输入user_id="1 or 1 = 1"。结果将是:

cursor.execute("DELETE FROM users WHERE id = 1 or 1 = 1")

可能会从您宝贵的用户表中删除所有用户。

因此,请改用:

cursor.execute("DELETE FROM users WHERE id = %d", user_id)

它不会创建一个字符串,编译并执行它,但是编译SQL语句,然后插入变量,然后执行它,这样更安全

答案 1 :(得分:0)

在问自己这个问题之前,有两件事我建议稍微研究一下。

首先,您依赖于模块范围内的一堆全局变量。您在其他模块中看到使这些全局变量可见的这个问题只会在编写更复杂的程序时变得更糟。您应该开始考虑稍微涉及类,导入它们,实例化它们并查看单例等设计模式。在类下定义一堆重要的列表,变量等,然后导入它们并在函数之间传递它们的实例,这样更容易和更清晰。面向对象是pythonic。

其次,您的功能在概念上看起来更像子程序。最好将功能视为......井......功能。他们应该采取一些参数(输入)并产生(即返回)一些输出。避免试图操纵全局变量,这很容易成为问题,并且更多地考虑使用输入来创建和返回输出。

研究并结合这些概念以及代码应该存在的答案将变得更加清晰。