如何从0搭建用户成长体系?

在我刚开始接触Python语言的日子里,我最喜欢做的事情之一是坐在解释器旁使用内置help功能来检查类和方法,决定下一个要敲的内容。这个功能导入一个对象,遍布它的成员,取出文档注释,生成一个类似manpage的输出,从而帮助你找到如何使用正在检查的对象的方法。

它被内置成一个标准库的美妙之处在于通过代码直接生成输出,它为我这样的懒人间接地强调了一个编码风格,我就想着在尽量少做额外的工作的情况下维护文档。尤其是如果你已经为你的变量和函数选择直接的名字。 这种风格涉及到向你的函数和类添加文档字符串,以及通过用下划线前缀来正确地识别私有成员和受保护成员。

Help on class list in module builtins:

class list(object)

| list() -> new empty list

| list(iterable) -> new list initialized from iterable’s items

|

| Methods defined here:

|

| __add__(self, value, /)

| Return self+value.

...

| __iter__(self, /)

| Implement iter(self).

...

| append(...)

| L.append(object) -> None -- append object to end

|

| extend(...)

| L.extend(iterable) -> None -- extend list by appending elements from the iterable

|

| index(...)

| L.index(value, [start, [stop]]) -> integer -- return first index of value.

| Raises ValueError if the value is not present.

...

| pop(...)

| L.pop([index]) -> item -- remove and return item at index (default last).

| Raises IndexError if list is empty or index is out of range.

|

| remove(...)

| L.remove(value) -> None -- remove first occurrence of value.

| Raises ValueError if the value is not present.

...

| ----------------------------------------------------------------------

| Data and other attributes defined here:

|

| __hash__ = None

在Python解释器上运行help(list)的输出。

帮助功能实际上是使用 pydoc 模块生成其输出,它也可以从命令行运行,以产生您路径中任何可导入模块的文本或 html 表示。

不久以前,我需要编写更细致,更正式的设计文档。而作为一个 Markdown 的粉丝,我决定玩一玩mkdocs,看看是否能获得我想要的结果。这个模块可以很容易地将你的 markdown 文档转化为一个样式美观的页面,并且,在发布为官方文档之前,允许你对其做更改。它提供了一个 readthedocs 模板,深圳还提供了一个简单的命令行界面,来把你的修改推送到 GitHub Pages 里面。

在完成了我最初的描述设计决策和注意事项的文本后,我想加上一些细节,描述我正在开发的实际接口方法。因为我已经为大部分的功能写了定义,我想从源代码自动生成参考页面,还希望这个能在 markdown 里面。这样的话,只要我想跑 mkdocs,它就可以连同我文档的其余部分,一起渲染成 html。

然而,事实上还没有一种从源码生成 markdown 的默认方式,除了一些插件。后来,我不断在谷歌上查询,我还是不满意我发现的插件——很多东西都过时了,没有人维护了,或者输出的东西不是我需要的——因此,我决定写一个我自己的项目。

“inspect 模块提供了几个有用的函数来帮助我们获取生存着的对象信息... ” — Python 文档

检查!

Inspect,源自于标准程序库,它不仅允许你查看较低级别的 python 框架和代码对象,它还提供很多方法来检查模块和类,帮你发现可能感兴趣的的项目。这个也就是之前提到的用来生成帮助文件的 pydoc。

浏览一下在线文档,你会发现许多跟我们所做的尝试相关的方法。最重要的几个是getmembers(),getdoc() 和 signature(),还有许多给 getmembers 做滤波器的 is... 功能。拥有这些,我们可以轻易地循环访问很多功能,包括区分生成器和协同程序,并可以按需要递归到任何一个类以及内部。

导入编码

如果我们要去检查一个对象,不管它是什么,第一步要做的是提供一个导入进我们的命名空间的原理。为何要讨论导入呢?这取决于你想要做什么,还有很多需要担心的,包括虚拟环境,自定义代码,标准模块和重命名。情况会容易混淆,搞错的话会需要一些时间去整理清楚。

我们当然还有些选择,更复杂的是直接从pydoc重用 safeimport (),当出现问题时,为我们解决很多特例和ErrorDuringImport类的特别条款。然而,如果我们对我们的环境需要更高的控制,我们自己简单地运行__import__(modulename)也是可能的。

另一个需要记住的是每一个代码的执行路径。可能会用到 sys.path.append() 的一个目录来进入我们寻找的模块。我的用例 我的用例是从命令行和被检查的模块的路径中的目录执行,所以,我将当前目录添加到 sys.path,这足以解决典型的导入路径问题。

按照上述方式,我们的导入函数会如下所示:

def generatedocs(module):

try:

sys.path.append(os.getcwd()) # Attempt import

mod = safeimport(module) if mod is None:

print("Module not found")

# Module imported correctly, let’s create the docs

return getmarkdown(mod) except ErrorDuringImport as e:

print("Error while trying to import " + module)

决定输出

在继续之前,你需要一个关于如何组织生成 markdown 输出的心理图像。思考:你需要一个不递归到自定义类的浅的引用吗?我们想要包含哪些方法?内置功能会怎么样?是用_还是__方法?我们应该如何呈现函数签名?我们应该拉注释吗?

我的选择如下:

·每个运行一个 .md 文件,其中包含递归到正在检查的对象的任意子类中生成的信息。

·只包括我创建的自定义代码,没有来自导入的模块的信息。

·每一项的输出必须用第二级 markdown 标题(##)标识。

·所有头文件必须包含正在描述的项的完整路径(module.class.subclass.function)。

·将完整的函数签名作为预格式化文本。

·为每个标题提供锚点,以便轻松的链接到文档及文档本身内容。

·任何以_或者__开头的函数都不做文档记录。

整合在一起

一旦对象被导入,我们可以开始检测了。这是一个简单的例子,重复调用 getmembers(object, filter),过滤器是一个有用的 is 函数。你能够发现 isclass 和 isfunction,其它相关的方法都是 is开头的,例如,ismethod , isgenerator , iscoroutine。这都取决于你是否想写一些通用的,可以处理所有的特殊情况,或一些更小的和更特殊的源代码。我坚持前两点,因为我不用把采用3个不同方法来创建我想要的格式化模块,类和功能。

def getmarkdown(module):

output = [ module_header ]

output.extend(getfunctions(module)

output.append("***\n")

output.extend(getclasses(module))

return "".join(output)def getclasses(item):

output = list() for cl in inspect.getmembers(item, inspect.isclass): if cl[0] != "__class__" and not cl[0].startswith("_"): # Consider anything that starts with _ private

# and don’t document it

output.append( class_header )

output.append(cl[0])

# Get the docstring

output.append(inspect.getdoc(cl[1]) # Get the functions

output.extend(getfunctions(cl[1])) # Recurse into any subclasses

output.extend(getclasses(cl[1]) return outputdef getfunctions(item): for func in inspect.getmembers(item, inspect.isfunction):

output.append( function_header )

output.append(func[0]) # Get the signature

output.append("\n```python\n)

output.append(func[0])

output.append(str(inspect.signature(func[1]))

# Get the docstring

output.append(inspect.getdoc(func[1])

return output

当要格式化大文本和一些编程代码的混合体时,我倾向于把它作为一个在列表或元组中的独立项目,用 "".join() 来合并输出。在写作的时候,这种方法其实比基于插值的方法(.format 和 %)更快。然而,python 3.6 的新字符串格式化将比这更快,更具可读性。

你可以看到,getmembers() 返回一个元组与对象的名称在第一位置和第二位置的实际对象,我们可以用递归遍历对象层次。

对于检索到的每一个项目,可能使用 getdoc() 或 getcomments() 获取文档字符串和注释。对于每一个功能,我们可以使用 signature() 得到 Signature 对象 ,它表示其位置参数和关键字参数的默认值和任何注释,为我们提供了产生简单直接的描述和良好风格的文本,有助于我们理解用户我们写代码的意图。

其他考虑因素和非预期后果

请注意,上面的代码只是示例代码,只是让你大概真的最终产品应该是什么样子。在最终确定产品之前,还有很多其他注意事项:

·getfunctions 和 getclasses 将显示模块中导入的所有方法和类。包括内置程序包,以及来自外部软件包的任何东西,所以你必须过滤掉更多的 for 循环。我在检查过程中使用模块的 __file__ 属性,不管它包含什么项。换句话说,如果项在我正在执行的路径中存在的模块内定义,则包含它(使用 os.path.commonprefix())。

·有一些 gotcha 的文件路径,导入层次结构和名称。像通过 __init__.py 将 moduleX 导入到包中时,你可以通过 package.moduleX.function 访问他的函数方法,但是全称将会是 package.moduleX.moduleX.function—通过 moduleX.__name__ 返回的名称。你或许不在乎这个区别,但是我在乎,所以这是在迭代过程中需要记住的事情。

·你会从内置程序库中导入类和任何其他不包含 __file__ 的东西,如果你进行任何如上所述的过滤,那么检查是必要的。

·因为这是 markdown,而我们只是导入 docstrings,你可以在你的 docstrings 中包含 mardown 语法,它会美观漂亮的呈现在页面中。然而,这意味着你应该注意正确的转义 docstrings,这样他才不会破坏生成的 HTML。

示例输出

我在 sofi 包-精确的说是 sofi.app 模块运行生成器,下面是它创建的 markdown 内容。

# sofi<a name="sofi"></a><a name="sofi.__init__"></a>### [sofi](#sofi).\_\_init\_\_

```python

__init__(self)

```

<a name="sofi.addclass"></a>

### [sofi](#sofi).addclass```python

addclass(self, selector, cl)```

Add the given class from all elements matching this selector.

下面是通过 mkdocs 运行它产生 readthedocs 主题页面后的最终结果(不包括函数注释)的示例。

我相信你已经知道,使用这些机制自动生成文档,会生成完整、精确和最新的模块信息,这些信息在你编写代码的时候可以进行维护和编写,且操作简单 。我强烈建议每个人都试一试。

在结束之前,我想再补充一点,mkdocs 并不是唯一的文档包,还有其他一些使用广泛的系统,如 Sphinx(mkdocs 基于此开发 )和 Doxygen,他们都能实现我们以上讨论的事项。然而,我比较通过练习来学习和了解更多关于 Python 内部机制和其随附的工具。

来源:开源中国

时间: 2024-09-30 08:28:20

如何从0搭建用户成长体系?的相关文章

视频直播的用户体验体系与质量监控方案

转自:https://www.upyun.com/opentalk/396.html 首页 > Open Talk NO.42 | 2018 音视频技术沙龙·上海站 > 视频直播的用户体验体系与质量监控方案 讲师简介 战旗直播高级流媒体研发工程师,2012年进入直播行业,先后在奥点云.战旗直播从事流媒体开发工作:2013年独立完成<RTMP协议规范1.0>的中文翻译:对于Windows.Android.iOS平台的直播和播放框架都有一定的研究. 6月24日,又拍云Open Talk

Azkaban 2.5.0 搭建

一.前言 最近试着参照官方文档搭建 Azkaban,发现文档很多地方有坑,所以在此记录一下. 二.环境及软件 安装环境: 系统环境: ubuntu-12.04.2-server-amd64 安装目录: /usr/local/ae/ankaban JDK 安装目录: export JAVA_HOME=/usr/local/ae/jdk1.7.0_51 Hadoop 安装目录 export HADOOP_HOME=/usr/local/ae/hadoop-1.2.1 Mysql 版本:mysql-s

基于 Laravel (5.1) & Ember.js (1.13.0) 的用户授权系统

Laravel 本身提供了完整的用户授权解决方案,对于由 PHP 驱动的多页面应用,Laravel 能够完美解决用户授权问题.但是在 SPA 中,laravel 退化成一个 API server,页面路由和表单提交完全由前端框架控制,此时面临2个问题: 如何在前端实现页面访问权限控制? 如何对 ajax 请求做授权? 如何在前端实现页面访问权限控制? Ember.js 1.13.0 没有提供 authentication 功能,我使用了一个名为 ember-simple-auth 的第三方扩展.

&lt;模电学习1&gt;Multisim 12.0 搭建并仿真51单片机最小系统

环境: 系统环境: win7 64位 软件平台:Multisim 12.0 目的: 刚毕业,但是模电知识也忘得差不多了,加之自己想搞搞硬件设计,如果只是看模电书,不实践,还是终觉浅.当做兴趣一样学学模电,仿真仿真.Multisim的MCU少,就拿51来练练手,搭建51单片机仿真系统,配合着记录一下书本的知识. 概述: 最后使用Multisim 12.0搭建出来的最小系统为图1-1所示,通过编写程序可以使LED1循环闪烁. 图1-1 正常来说,51单片机最小系统一般包括单片机.晶振电路.复位电路,

C#微信公众号开发之网页授权oauth2.0获取用户基本信息(二)

C#微信公众号开发之网页授权oauth2.0获取用户基本信息(一) 中讲解了如果通过微信授权2.0snsapi_base获取已经关注用户的基本信息,然而很多情况下我们经常需要获取非关注用户的信息,方法如下: 第一步和之前讲的一样:获取code,但是scope使用方法是snsapi_userinfo; 第二步,根据code获取openid和access_token(此处的access_token是通过网页授权code换取的不是我们之前讲的全局的票据),代码: 1 /// <summary> 2

袋鼠云数据中台专栏(七):用户标签体系建设的四字箴言

本文作者:子玺 袋鼠云数据中台解决方案专家.拥有近10年大数据从业经验,拥有PMP项目管理资格认证,精通数据类项目的开发实施和管理.曾服务过国家工商总局.北京市工商局.北京市财政局.广州开发区大数据局.平湖人社局.海盐人社局等行政单位,担任多个大型数据项目的数据应用咨询顾问/项目经理. 正文: 一.什么是用户画像?什么是标签? 当我们从互联网时代逐渐步入大数据时代后,企业及消费者行为不可避免地要面临一系列改变与重塑.其中最大的变化莫过于,消费者的一切行为在企业面前似乎都将是「可视化」的,然而,「

.Net Core 3.0 WebAPI && MySQL 8.0搭建详情

微软在2019年9月24日发布了dotNet Core 3.0和C# 8.0,添加了许多新Features,详情点我.无疑dotNet Core 3.0和一个月之后即将发布的dotNet Core 3.1对于dotNet来说是一个重要的里程碑. 对于MySQL而言,现在越来越多的商业公司使用MySQL来作为自己的主要数据库,虽然MySQL已经迎来了8.0的版本,有着更完善的数据能力,更好的性能,但是还是有很多公司在新项目上使用MySQL5.7.我在技术上很鄙视这样的做法,一旦使用的老技术Out

思科CME9.0搭建企业VOIP电话

一.项目需求分析 15-30个用户作用需要实现VOIP 语音人工座席 一台思科3945路由器+FXO+FXS实现语音网关 思科IP×××CP-9971若干台 内部实现IP×××互打,包括远端站点,所有流量全部走IP网络 外部PSTN呼入,经过语音网关实现模拟信号到数字信号的转换,并且需要自动语音按键提醒,根据呼入用户的输入在进行内部转接 接入层使用华为POE交换机,并且实现二层安全接入 DHCP服务器和文件服务使用Linux服务器部署 二.配置步骤总结 思科官网下载相关软件,导入CSICO 39

Redis Cluster 3.0搭建与使用

Redis Cluster终于出了Stable,这让人很是激动,等Stable很久了,所以还是先玩玩. 一. 集群简单概念. Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation). Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为. Redis 集群通过分区(partition)来提供