我正在编写一个简单的 Python Web 应用程序,它由几页为 iPhone 格式化的业务数据组成。我对 Python 编程很熟悉,但我对 Python 的“习惯用法”不太熟悉,尤其是关于类和对象。Python 的面向对象设计与我使用过的其他语言有所不同。因此,即使我的应用程序正在运行,我还是很好奇是否有更好的方法来实现我的目标。
细节:人们通常如何在 Python 中实现请求-转换-渲染数据库工作流?目前,我正在使用 pyodbc 获取数据,将结果复制到对象的属性中,使用这些对象的列表执行一些计算和合并,然后呈现对象列表中的输出。(下面的示例代码,SQL 查询已编辑。)这正常吗?有没有更好的办法?由于我对 Python 的相对无知,我偶然发现了任何特定的“陷阱”吗?我特别关心我是如何使用空的“Record”类实现行列表的。
class Record(object):
pass
def calculate_pnl(records, node_prices):
for record in records:
try:
# fill RT and DA prices from the hash retrieved above
if hasattr(record, 'sink') and record.sink:
record.da = node_prices[record.sink][0] - node_prices[record.id][0]
record.rt = node_prices[record.sink][1] - node_prices[record.id][1]
else:
record.da = node_prices[record.id][0]
record.rt = node_prices[record.id][1]
# calculate dependent values: RT-DA and PNL
record.rtda = record.rt - record.da
record.pnl = record.rtda * record.mw
except:
print sys.exc_info()
def map_rows(cursor, mappings, callback=None):
records = []
for row in cursor:
record = Record()
for field, attr in mappings.iteritems():
setattr(record, attr, getattr(row, field, None))
if not callback or callback(record):
records.append(record)
return records
def get_positions(cursor):
# get the latest position time
cursor.execute("SELECT latest data time")
time = cursor.fetchone().time
hour = eelib.util.get_hour_ending(time)
# fetch the current positions
cursor.execute("SELECT stuff FROM atable", (hour))
# read the rows
nodes = {}
def record_callback(record):
if abs(record.mw) > 0:
if record.id: nodes[record.id] = None
return True
else:
return False
records = util.map_rows(cursor, {
'id': 'id',
'name': 'name',
'mw': 'mw'
}, record_callback)
# query prices
for node_id in nodes:
# RT price
row = cursor.execute("SELECT price WHERE ? ? ?", (node_id, time, time)).fetchone()
rt5 = row.lmp if row else None
# DA price
row = cursor.execute("SELECT price WHERE ? ? ?", (node_id, hour, hour)).fetchone()
da = row.da_lmp if row else None
# update the hash value
nodes[node_id] = (da, rt5)
# calculate the position pricing
calculate_pnl(records, nodes)
# sort
records.sort(key=lambda r: r.name)
# return the records
return records
Run Code Online (Sandbox Code Playgroud)
空的 Record 类和(通常)应用于单个 Record 的自由浮动函数暗示您没有正确设计您的类。
class Record( object ):
"""Assuming rtda and pnl must exist."""
def __init__( self ):
self.da= 0
self.rt= 0
self.rtda= 0 # or whatever
self.pnl= None #
self.sink = None # Not clear what this is
def setPnl( self, node_prices ):
# fill RT and DA prices from the hash retrieved above
# calculate dependent values: RT-DA and PNL
Run Code Online (Sandbox Code Playgroud)
现在,您的calculate_pnl( records, node_prices )操作更加简单并且可以正确使用该对象。
def calculate_pnl( records, node_prices ):
for record in records:
record.setPnl( node_prices )
Run Code Online (Sandbox Code Playgroud)
重点不是以小的方式简单地重构代码。
要点是: 类封装了责任。
是的,看起来空洞的类通常是一个问题。这意味着责任分散在其他地方。
类似的分析也适用于记录的收集。这不仅仅是一个简单的列表,因为集合(作为一个整体)具有它执行的操作。
“请求-转换-渲染”不太正确。您有一个模型(Record 类)。模型的实例被构建(可能是因为请求)。模型对象负责它们自己的状态转换和更新。也许它们由某个检查其状态的对象显示(或渲染)。
正是“转变”步骤经常将责任分散到各处,从而违反了良好的设计。“转换”是非对象设计的遗留物,在非对象设计中,责任是一个模糊的概念。
| 归档时间: |
|
| 查看次数: |
3325 次 |
| 最近记录: |