阿里云的 Python SDK 是真的烂啊, 想起个 aliyunpythonsdksucks 项目组, 然后把他们的 sdk 封装一下

2019-01-22 17:00:12 +08:00
 LeoQ

槽多无口, 里面的接口还有 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 的属性值吗?

我这里想问一下大家, 如果我这么做了, 会收到律师函吗?

6322 次点击
所在节点    Python
34 条回复
susucoolsama
2019-01-23 08:08:12 +08:00
@qingtangsdk 这个回复应该是妹子客服回复的吧,这文笔不像是程序 gg....
est
2019-01-23 08:58:20 +08:00
代码烂不是槽点,依赖一个老掉牙的加密库才是
glasslion
2019-01-23 10:18:01 +08:00
@dongqihong
@bestkayle
@luozic
@Cbdy
你们高估阿里云了, 这代码就是让实习生抄出来的
Feiox
2019-01-23 10:51:21 +08:00
相比之下 微软的 azure python sdk 如同神赐一般
guanhui07
2019-01-23 14:25:16 +08:00
好像 java
LeoQ
2019-01-23 15:42:20 +08:00
@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 中是更友好的一种调用方法, 你觉得呢?
LeoQ
2019-01-23 15:47:04 +08:00
@est 新的已经不依赖了, 感恩
est
2019-01-23 16:18:34 +08:00
@LeoQ 那还挺不错。不过已经被我们用一个 5 行的 python 函数+urllib 给代替了。
abmin521
2019-01-23 16:30:46 +08:00
LeoQ
2019-01-23 16:38:04 +08:00
@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 这些冗长的字符的.

这些快捷方式, 阿里做了吗? 没有.
LeoQ
2019-01-23 16:40:36 +08:00
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 的重度用户,其实不太明白为什么有“动态设置属性”这种需求。你有什么场景是必须要动态设置属性的嘛?
LeoQ
2019-01-23 21:36:09 +08:00
我最后提到动态属性的意思是, 属性值是有好处的, 代码风格上会看起来更简单易读.

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 都没有用到.
Trim21
2019-01-23 22:13:46 +08:00
看着真像自动生成的…

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/529522

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX