这算是符合Python风格的API设计策略吗?
我想先介绍一下我提问的背景:我正在为我的公司用Python开发一个不依赖于特定支付网关的支付API。目前,我只写了支持Authorize.net的代码,想请一些比我更有经验的Python程序员给我反馈,看看我的API设计是否清晰。
我选择自己动手做是因为现有的其他包感觉像是随便做的,或者是专门针对Authorize.net的(我想写一个更通用的包,界面更简洁)。我从一个特别的包(pythorize)得到了灵感,但我不喜欢他们的API设计。
在我开始描述我的工作之前,这里有我在bitbucket上的公共代码库链接:paypy(给想使用它的人提个醒:代码是稳定的,但文档非常缺乏)。
我目前的策略是使用嵌套字典,并将其传递给支付方法类的构造函数。下面是一个在Authorize.net CIM API上创建新用户资料的例子:
>>> options = {'tran_key' : 'test_tran_key',
... 'login' : 'developer_login',
... 'testing' : True,
... 'validation': 'testMode',
... 'customer': {'description': 'Some description of the customer profile',
... 'id' : 22,
... 'email' : 'johnny_doe@gmail.com'},
... 'billing': [{'type': 'individual',
... 'profile': {'city' : 'Carlsbad',
... 'state' : 'California',
... 'zip' : '92009',
... 'firstname' : 'John',
... 'address' : '12 Alicante Rd. Suite 9',
... 'lastname' : 'Doe',
... 'country' : 'USA',
... 'phone' : '(858) 557-2674'},
... 'payment': {'card': {'ccv' : '524',
... 'number' : '4111111111111111',
... 'expiration' : '2014-04'}}},
... {'type' : 'individual',
... 'profile' : {'city' : 'Las Vegas',
... 'state' : 'Nevada',
... 'zip' : '79112',
... 'firstname' : 'John',
... 'address' : '78 Cloud Front',
... 'lastname' : 'Doe',
... 'country' : 'USA',
... 'phone' : '(858) 557-2674'},
... 'payment': {'card': {'ccv' : '499',
... 'number' : '4111111111111111',
... 'expiration' : '2012-11'}}},
... {'profile': {'city' : 'Carlsbad',
... 'state' : 'California',
... 'zip' : '92009',
... 'firstname' : 'John',
... 'address' : '12 Alicante Rd. Suite 9',
... 'lastname' : 'Doe',
... 'company' : 'Xmarks',
... 'country' : 'USA',
... 'phone' : '(858) 557-2674'},
... 'payment': {'bank': {'name_on_account' : 'John Doe',
... 'account' : '829330184383',
... 'type' : 'checking',
... 'name' : 'Bank of America',
... 'routing' : '122400724'}}}],
... 'shipping': [{'city' : 'Carlsbad',
... 'state' : 'California',
... 'zip' : '92009',
... 'firstname' : 'John',
... 'address' : '12 Alicante Rd. Suite 9',
... 'lastname' : 'Doe',
... 'country' : 'USA',
... 'phone' : '(858) 557-2674'}]}
>>> profile = Profile(options)
>>> result = profile.create()
>>> result.code
'I00001'
>>> print 'Customer Profile ID:' + str(result)
Customer Profile ID: 2758851
>>> print 'Customer Payment Profile IDs:' + repr(result.payment_ids)
Customer Payment Profile IDs: ['2380878', '2380879', '2380880']
>>> print 'Customer Shipping Profile IDs:' + repr(result.shipping_ids)
Customer Shipping Profile IDs: ['2427568']
>>>
>>>
>>> options = {'id' : str(result),
... 'tran_key' : '86U5pvA9TcxZ5b8D',
... 'testing' : True,
... 'login' : '5b3PhGX68'}
>>> profile = Profile(options)
>>> result = profile.remove()
>>> result.code
'I00001'
>>> ^D
你会注意到我使用了一些魔法方法(比如str等)来处理结果对象。我在AIM和ARB方法中也使用了这种字典策略,觉得这是向支付API传递“选项”的最简单方法——因为将来会有GoogleCheckout、Paypal等的适配器。
我还有一个想法是使用描述符和对象,而不是字典,来传递选项数据给适配器。
像所有支付网关API(特别是PayPal和Authorize.net)的接口,通常都比较杂乱,并且没有标准化,所以很难避免一些依赖于特定网关的选项。
1 个回答
在Python中,深层嵌套的字典可能并不少见,可能有人觉得这很“Python风格”,但我觉得这其实并不是个好主意,所以我认为这并不算真正的Python风格。
我会选择用嵌套的类结构来代替。这样会更清晰,而且还能让你进行类型检查,这样更安全。
实际上,我可能会使用一些模式模块来实现这个功能。
那么,你打算怎么输入这些数据呢?人们当然不应该直接输入Python代码,对吧?