槽多无口, 里面的接口还有 v20140815 , 所有的 class 看起来都一样, 一样的长, 一样的难以理解
举个例子 CreateOnlineDataBaseTaskRequest
# 阿里云的代码
from aliyunsdkcore.request import RpcRequest
class CreateOnlineDatabaseTaskRequest(RpcRequest):
def __init__(self):
RpcRequest.__init__(self, 'Rds', '2014-08-15', 'CreateOnlineDatabaseTask','rds')
def get_ResourceOwnerId(self):
return self.get_query_params().get('ResourceOwnerId')
def set_ResourceOwnerId(self,ResourceOwnerId):
self.add_query_param('ResourceOwnerId',ResourceOwnerId)
def get_MigrateTaskId(self):
return self.get_query_params().get('MigrateTaskId')
def set_MigrateTaskId(self,MigrateTaskId):
self.add_query_param('MigrateTaskId',MigrateTaskId)
def get_DBName(self):
return self.get_query_params().get('DBName')
def set_DBName(self,DBName):
self.add_query_param('DBName',DBName)
def get_ResourceOwnerAccount(self):
return self.get_query_params().get('ResourceOwnerAccount')
def set_ResourceOwnerAccount(self,ResourceOwnerAccount):
self.add_query_param('ResourceOwnerAccount',ResourceOwnerAccount)
def get_ClientToken(self):
return self.get_query_params().get('ClientToken')
def set_ClientToken(self,ClientToken):
self.add_query_param('ClientToken',ClientToken)
def get_OwnerAccount(self):
return self.get_query_params().get('OwnerAccount')
def set_OwnerAccount(self,OwnerAccount):
self.add_query_param('OwnerAccount',OwnerAccount)
def get_DBInstanceId(self):
return self.get_query_params().get('DBInstanceId')
def set_DBInstanceId(self,DBInstanceId):
self.add_query_param('DBInstanceId',DBInstanceId)
def get_CheckDBMode(self):
return self.get_query_params().get('CheckDBMode')
def set_CheckDBMode(self,CheckDBMode):
self.add_query_param('CheckDBMode',CheckDBMode)
def get_OwnerId(self):
return self.get_query_params().get('OwnerId')
def set_OwnerId(self,OwnerId):
self.add_query_param('OwnerId',OwnerId)
# 我想要的代码
class DatabaseTask:
def __init__(self, **kwargs):
self.migrate_task = migrate_task
self.db_name = db_name
self.resource_owner = resource_owner
self.token = token
self.check_db_mode = check_db_mode
def run():
# make some request
if __name__ == '__main__':
new_task = DatabaseTask(migrate_task=1, db_name='some_db',
resource_owner='some_user', token='some_token',
check_db_mode='some_mode')
result = new_task.run()
result.fetch()
为什么不写成 一个 DatabaseTask 对象, 对象有几个属性值 Instance_id
等 ,然后再调用 DatabaseTask.create()
这些 set 和 get 的方法, 不就是实现了 python 的属性值吗?
我这里想问一下大家, 如果我这么做了, 会收到律师函吗?
1
glasslion 2019-01-22 17:19:35 +08:00 2
这种代码一看就是 先有 Java 的 SDk, 实现 Python SDK 时直接照搬了 Java 的实现。 这种行为虽然挺恶心的, 但毕竟是最节省开发资源的做法,也只能忍了 。
Google 的 Python SDK 一样大量这种代码。 抛开代码风格的问题, 阿里云 Python SDK 早期的代码质量极差, 连培训班水平都不如。 目前的质量已经比以前好太多了。 https://github.com/aliyun/aliyun-openapi-python-sdk/issues/43 |
2
www5070504 2019-01-22 17:21:55 +08:00 3
支持 这种带有 java “风味”的 python 代码是 python 中的毒瘤
|
3
qq976739120 2019-01-22 17:24:07 +08:00 1
我之前看他们的代码以为是我功力不够的原因....原来是他们写的查,汗!
|
4
wuhaochen999 2019-01-22 17:43:33 +08:00 1
get set 有啥问题
|
5
Cbdy 2019-01-22 18:08:59 +08:00 via Android 1
估计是直接根据 Java SDK 代码用编译器编译成 Python 代码的(代码生成)吧,其他语言类似。这样只需要维护一份 Java 代码即可
|
6
wusphinx 2019-01-22 18:10:11 +08:00 1
在保证代码正确性的前提下,代码不够 pythonic 还是可以接受的
|
7
alvin666 2019-01-22 18:13:19 +08:00 via Android 1
妈耶
这代码要人命啊 |
8
janxin 2019-01-22 18:15:22 +08:00 1
支持,每次用 Python 的 SDK 用的想死
|
9
aldslvda 2019-01-22 19:05:58 +08:00 1
java 味太浓
|
10
dongqihong 2019-01-22 19:32:18 +08:00 1
这是自动化生成的接口代码。。。
|
11
shaodamao 2019-01-22 19:50:50 +08:00 1
之前用过他们的 python sdk,sdk 代码应该是根据 api 生成的。
可以用 aliyunsdkcore.request 中的 CommonRequest,自己封装了个通用的方法,将就用一下 orz |
12
KgM4gLtF0shViDH3 2019-01-22 20:26:01 +08:00 1
这明显是自动生成的代码。。和机器人较真干啥。
|
13
iorilu 2019-01-22 22:18:37 +08:00 1
这个 sdk 是干啥用的
|
14
Faiz555 2019-01-22 23:03:28 +08:00
用过阿里云的短信 SDK,调用的时候感觉巨恶心
|
15
luozic 2019-01-22 23:49:45 +08:00 via iPhone
这种要么是基于 Java 生成,要么直接根据 OAI 类似 swagger 的规范直接一把生成,不分 java 还是啥
|
16
qingtangsdk 2019-01-22 23:59:57 +08:00 6
亲们,大家好,我是阿里云 SDK 的研发 GG,看到吐槽就赶紧诚惶诚恐地过来啦^_^。首先感谢大家对阿里云 Python SDK 的关注,这里跟大家十分十分(* 1024 )诚恳地道歉,Python SDK 没有按照 Python 的编码规范设计,我们没做好,给大家造成了不好的体验,对不起!
为了解决好这个这个问题呢,我们阿里云 SDK 研发团队正在抓紧时间编写阿里云 Python SDK 的第二版,目前是刚起步,项目代码在这里: https://github.com/aliyun/alibabacloud-python-sdk-v2 请大家过目。亲们可以在: https://github.com/aliyun/alibabacloud-python-sdk-v2/issues 这里吐槽,我们会抓紧时间改进哦! 亲们的批评就是我们改进的动力,为此我们会不断努力,感谢对阿里云的关心! |
17
lxml 2019-01-23 00:26:16 +08:00 via Android
想起了金山云的 SDK,fork 自 aws 的,然后大家表示读不懂代码,宁愿调用我的 http 接口都不愿意自己去接入。
|
18
niubee1 2019-01-23 01:26:42 +08:00
在国内的项目组里呢一般都只有边缘人和实习生才会干搞 SDK 这类事情, 质量差是很自然的事情
|
19
incompatible 2019-01-23 02:40:53 +08:00
v20140815 有什么问题? 公有云产品的 API 必须向下兼容,即便某天发布了 v2020xxxx,先前的 v20140815 也是要永久保留的。
SDK 里 client 与 request 各司其职,request 负责封装 API 的参数; client 负责从 request 取参数、做签名、拼 url 发请求、解析返回值。且各个产品的各个 API 都 follow 此 pattern,学一次就会用所有产品的 API 了。 你自己定义的 DatabaseTask 相比之下并没看出有什么优点,仅仅是满足了你自己的偏好而已。 |
20
busyboy 2019-01-23 07:54:59 +08:00
我已经很知足了,比部分云厂商的好很多
|
21
susucoolsama 2019-01-23 08:08:12 +08:00 via iPhone
@qingtangsdk 这个回复应该是妹子客服回复的吧,这文笔不像是程序 gg....
|
22
est 2019-01-23 08:58:20 +08:00 via Android
代码烂不是槽点,依赖一个老掉牙的加密库才是
|
23
glasslion 2019-01-23 10:18:01 +08:00
|
24
Feiox 2019-01-23 10:51:21 +08:00 1
相比之下 微软的 azure python sdk 如同神赐一般
|
25
guanhui07 2019-01-23 14:25:16 +08:00
好像 java
|
26
LeoQ OP @incompatible 谢谢你的不留情面的批评, 可能是我孤陋寡闻了, 但是国外的云厂商, 我在 aws 的 sdk https://github.com/boto/botocore/tree/develop/botocore 里没有发现版本的印记, 在 azure 的 sdk 里, 版本的印记还存在, 但是一些最近有修改的模块已经没有了版本的文件夹 https://github.com/Azure/azure-sdk-for-python .
这说明带时间的版本已经不是最佳实践, azure 也在尝试改变这一点, 完全可以通过 SDK 的主版本进行控制 带时间的版本我认为也确实不友好, 比如 20140817 版本和 20180704 版本兼容吗? 用户是不清楚的 , 如果是类似 0.0.1 和 3.0.0 , 那么用户自己就有感觉, 这个代码可能是不兼容了,再参阅一下文档, 确实是不兼容的, 那么, 要么改代码, 要么安装低版本的 sdk. 我给出的版本确实是满足了自己的偏好, 但我认为是确实比之前的容易理解的, 把 get set 改为对对象的属性值操作 既然可以 ``` new_task = DatabaseTask() new_task.owner = 'me' print(new_task.owner) ``` 那么为什么要 ``` new_task = DatabaseTask() new_task.set_owner('me') print(new_task.get_owner('me')) ``` 而且属性值也天生支持动态获取, 动态设置 ``` new_task.setattr('owner','me') new_task.getattr('owner') ``` 如果是函数的话, 没有办法做到动态的. 我认为这在 python 中是更友好的一种调用方法, 你觉得呢? |
29
abmin521 2019-01-23 16:30:46 +08:00
|
30
LeoQ OP @abmin521 https://github.com/Azure/azure-sdk-for-python/blob/master/azure-mgmt-dns/azure/mgmt/dns/models.py
确实是有, 但是你看一下这里, 在 models 层做了一个快捷方式, 默认情况下, 是调 v2018_03_01_preview.models 的, 对于开发者来说, 如果版本的需求, 是可以不用在代码里体现 v2018_03_01_preview 这些冗长的字符的. 这些快捷方式, 阿里做了吗? 没有. |
31
LeoQ OP |
32
incompatible 2019-01-23 20:41:38 +08:00
@LeoQ
关于 API 的向下兼容:并非指的是 v2020xxxx 要兼容 v20140815 的功能,而是说即便发布了 v2020xxxx 后,v20140815 依然可用并且行为不变。 对于调用方来说,升级 api 版本或者 sdk 版本都是非常 critical 的事,在升级过程中,校验 sdk 或 api 的版本兼容性是必不可少的步骤。当然如你所说,sdk 版本和 api 版本强绑定是个糟糕的设计。 属性和 setter 之间的取舍,你看一下阿里 sdk 的源码,它是在 setter 里把 params 放到了父类的一个 dictionary 里了。另外基于它代码中有 add_query_param()的字样,我推测除了 query params 应该还有 body params、header_params、这些是基于 api metadata 生成 sdk 的 request 就固定下来的,如果不用 setter 的方式就需要额外的 metadata 来描述一个 param 的位置到底是在 query、body 还是 header 中。 最后关于动态设置 request 的属性,我自己是阿里云 ecs/rds/slb 等产品 java sdk 的重度用户,其实不太明白为什么有“动态设置属性”这种需求。你有什么场景是必须要动态设置属性的嘛? |
33
LeoQ OP 我最后提到动态属性的意思是, 属性值是有好处的, 代码风格上会看起来更简单易读.
Python 和 Java 类似, 也可以有 setter 和 getter 函数 不一样的是, python 还有 property 装饰器, 加入这个装饰器, 就可以正常使用 student.age del(student.age)这种做法了 ``` class Student(object): def __init__(self): self._age = None @property def age(self): return self._age @age.setter def age(self, age): if isinstance(age, int): self._age = age return if isinstance(age, str) and age.isdigit(): age = int(age) self._age = age else: raise ValueError("age is illegal") @age.deleter def age(self): del self._age ``` 我还顺着翻到了它的 base 类 https://github.com/aliyun/aliyun-openapi-python-sdk/blob/master/aliyun-python-sdk-core/aliyunsdkcore/request.py 到了 base 依然是有着大量的普通的 set_XXX / set_XXX 方法. 而我因为他们代码都是 set_XXX 的, 我也得写这样冗长的代码, 为什么不改成上面的那种呢? 我的意思是, python 里有很多的语法糖可以做这些事情, 但是阿里云的 sdk 都没有用到. |
34
Trim21 2019-01-23 22:13:46 +08:00 via Android
看着真像自动生成的…
|