65.9K
CodeProject 正在变化。 阅读更多。
Home

面向 .NET 开发者的 Python

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.65/5 (14投票s)

2018年2月6日

CPOL

7分钟阅读

viewsIcon

50229

downloadIcon

706

从 .NET 开发者的角度看 Python

引言

我们将从 .NET 开发者的角度探索 Python。根据我的经验,当我们学习任何新的、相似的事物时,我们总是试图找到我们已经知道的东西,并检查在这里如何完成相同的事情。

使用代码

下载 PCC.DataAPI.zip

下载 PCC.DataAPI-v1-withNoVE.zip

安装与设置

安装和设置 Python 主要有两种方式。众所周知,微软为我们做了很多事情,所以我们先来看第一种。

a. .NET 的方式

微软旗舰级的 VS2017 提供了内置的 Python 选项。选择安装相同选项并更新设置,它基本上会为你完成所有事情。

 

b. 世界其他地方

信不信由你,有些开发者并不使用 Visual Studio ;)

  • 从 https://pythonlang.cn/downloads/ 下载最新稳定版本并进行安装。
  • 安装后,打开命令提示符并输入 pip –version,此命令应该能识别并显示已安装的 Python 版本。

c. MySQL

让我们完全开源,也获取我们将用于 REST API 的 MySQL。

从这里获取安装程序并安装它。

https://dev.mysqlserver.cn/downloads/windows/installer/

并创建一个表并插入一些测试数据。

CREATE TABLE `graphdata` (

  `id` int(11) NOT NULL,

  `descrption` varchar(45) DEFAULT NULL,

  `value` decimal(10,0) DEFAULT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

默认服务器

d. 一些常用包

  1. 获取 httpie 以从命令提示符调用 REST API。

pip install --upgrade httpie

  1. 获取 Web 服务器。

pip install waitress

  1. 连接到 MySQL。

pip install pymysql

快速健全性检查。

  • 创建“Hellp.py”文本文件并写入:
    • print("Hello Python! I am from .NET world")
  • 打开命令提示符。
  • 转到文件位置。
  • 输入文件名 - “Hellp.py”并回车。

太棒了,它运行了,我可以在控制台中看到结果,此时它引起了我的注意。我的意思是,只有一行代码就能运行,没有 import/using/class 或 function。

好的,这只是控制台,让我们看看它能用 REST API 做什么,现在先放下,继续主要话题。

  Visual Studio 中的项目模板

Visual Studio 自带了一些不错的、流行的内置 Python 项目模板。你可以选择其中任何一个开始编写代码,它们自带了所有必需的包。

我尝试了 Django,只是因为它的名字很吸引人,但不太喜欢它。

  在 Visual Studio 中安装 Python 包

如果你想在 Visual Studio 中安装任何包,也可以轻松地在 VS 中完成,它自带 IntelliSense(所有拼写错误者的初恋)。

搜索并安装我们将在此使用的 Falcon

 

我的选择 - Falcon

我发现(至少感觉)Falcon 简单快捷,你可以在这里找到很好的阅读资料 https://falconframework.org/

现在我们已经完成了故事铺垫,是时候开始行动了。

a.       解决方案结构

  • 让我们创建一个类似这样的解决方案结构(添加同名的文件夹和文件)。

  • 在项目中右键单击并转到属性。
  • 将 main.py 设置为启动文件。

 

b.      在你写代码之前

  • Python 不使用 { } 来定义作用域,而是使用 TAB,所以要注意缩进和对齐。
  • 一个 .py 文件不能同时包含制表符和手动空格。

c.       类创建

让我们创建一个通用类,用于对 JSON 进行十进制编码,令人惊讶的是,Python 的 JSON 包无法处理 decimal(在 json.dumps(..) 中)。

decimalEncoder.py

import falcon
import json
from decimal import Decimal as D

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, D):
            return float(obj)
        return json.JSONEncoder.default(self, obj)

在此文件中:

  • Import = C# 中的 using
  • decimal import Decimal as D
    • D = C# 中的 using alias
    • Decimal 是来自 decimal 文件/包的类。

d.       配置文件

我们有很多配置文件可供选择,我们使用简单方便的 ini 文件。

它是一个简单的键值对文件,有不同的部分。[DEV] 和 [QA]。

Config.ini

[DEV]

DBServer = localhost

User=root

Password=admin

Db=db1


[QA]

DBServer = localhost

User=root

Password=admin

Db=db1

我们将在 secData.py 中使用它。

e.       模块

让我们在 secData.py 中添加代码,这是包含大部分代码的模块。

secData.py

import json
import falcon
import pymysql
import configparser

from Utilities.decimalEncoder import DecimalEncoder

class SecData(object):

    def __init__(self,comingFrom):
        print("__init__, comingFrom:",comingFrom)
        config = configparser.ConfigParser()
        config.sections()
        config.read("config.ini")
        
        #Global level variable
        self.DBServer = config['DEV']['DBServer']
        self.Db = config['DEV']['Db']
        self.User = config['DEV']['User']
        self.Password = config['DEV']['Password']
    
    def getData(self,companyName):
        try:
             dbConnetion = pymysql.connect(host=self.DBServer,user=self.User,password=self.Password,db=self.Db)
             cursor = dbConnetion.cursor()
             sql = sql = "SELECT * FROM db1.table1"
             if (companyName.lower() != "all"):
                sql = "SELECT * FROM db1.table1 where descrption ='" + companyName + "'"
             print("sql:",sql)
             rowCount = cursor.execute(sql)
             rows = cursor.fetchall()
             jsonRows = []
             
             for row in rows:
                jsonRow = {
                        'id':row[0]
                        ,'descrption':row[1]
                        ,'value':DecimalEncoder().encode(row[2])}
                jsonRows.append(jsonRow)

        except OSError as err:
            print("OS error: {0}".format(err))
        except:
            print("Unexpected error:", sys.exc_info()[0])
        finally:
            cursor.close()
            return (jsonRows)
            

    def on_get(self, req, resp,companyName):
       
            print("companyName:",companyName)
            print("req.query_string:",req.query_string)
            jsonRows = self.getData(companyName)
        
            # Create a JSON representation of the resource
            resp.body = json.dumps(jsonRows, ensure_ascii=False)
            resp.status = falcon.HTTP_200
       

 

现在我们将逐行 walkthrough 代码并解释一些关键点。

f.      哪个代码首先执行?

def __init__(self,comingFrom):

我添加了 comingFrom,只是为了跟踪是谁在实例化它。

         这让我想起了 ASP.NET 的页面生命周期。

g.       全局变量

任何使用 self.xyz 的变量。

就像 ASP.NET MVC 中的 ViewBag 一样。

h.      读取配置文件

self.DBServer = config['DEV']['DBServer']

就像从 C# 的 DataTable 获取数据一样。

i.       路由

def on_get(self, req, resp,companyName):

前三个是标准参数;第四个用于从路由获取值。

我们将在 main.py 中使用它。

j.        查询字符串

def on_get(self, req, resp,companyName):

req 包含有关请求的大量信息,目前 req.query_string 会获取查询字符串。

k.       数据库连接

连接数据库非常直接。

  dbConnetion = pymysql.connect(host=self.DBServer,user=self.User,password=self.Password,db=self.Db)

is 我们的连接对象,cursor = dbConnetion.cursor() 是数据读取器。

l.      JSON 输出

json.dumps(..) 会从对象创建 JSON 并将其分配给 response 对象。

resp.body = json.dumps(jsonRows, ensure_ascii=False)

还将 response 设置为 200 以便一切正常。

resp.status = falcon.HTTP_200

m.        异常处理

就像 C# 一样,Python 也有更具体到更通用类型的异常处理。

  try:

       # any code

except OSError as err:

           print("OS error: {0}".format(err))

       except:

           print("Unexpected error:", sys.exc_info()[0])

       finally:

cursor.close()  

n.        代码执行入口点

既然我们已经将 main.py 设置为启动文件,让我们看看里面有什么。

main.py

import falcon

from SecDataModule.secData import SecData

api = application = falcon.API()

secData = SecData("main")

api.add_route('/secdata', secData)

api.add_route('/secdata/{companyName}', secData)

if __name__ == "__main__":

    # Use Python's built-in WSGI reference implementation to run

    # a web server for the application.

    from wsgiref.simple_server import make_server

    # Run the web server on localhost:8080

    print("Starting web app server")

    srv = make_server('localhost', 8080, api)

    srv.serve_forever()

 

  • .secData 是在不同文件夹中导入文件的方式。
  • '/secdata/{companyName}', secData) 就像 MVC 路由一样。secData 是将处理来自此路由的请求的那个。

o.      启动自己的 Web 服务器

启动 wsgiref 控制台基础服务器。

from wsgiref.simple_server import make_server

srv = make_server('localhost', 8080, api)

srv.serve_forever()

检查一下。

让我们做一些基本测试。

一个简单的请求以 获取所有 数据。

https://:8080/secdata/all

获取 特定 数据。

 

测试 查询字符串

https://:8080/secdata/Test1?id=1

在服务器控制台中:

 

响应

 

<!--[if !supportLists]-->  <!--[endif]--><o:p>

虚拟环境

正如智者所说:*“设置和使用虚拟环境对于 Python 来说是非常标准的做法”*,所以让我们来谈谈添加新的虚拟环境。

顾名思义,虚拟环境允许我们创建环境,在其中可以拥有不同版本的包、库,而不会与全局环境中安装的库发生冲突。

a.       添加虚拟环境

幸运的是 VS 也支持这一点,只需右键单击 Python Environments 并选择 Add Virtual Environment。

命名它,还可以选择更改解释器版本。

 

b.      快速失败测试

此时代码将无法运行,并应该抛出 falcon ModuleNotFoundError 错误。请记住,我们安装了两个包 Falcon 和 PyMySQL,现在它们在单独的环境中。为了使其正常工作,我们需要将这两个包添加到我们的 v.e. 中。

c.       Requirements.txt

这就像 C# 的 packages.config,其中包含所有必需的包,尽管我发现它更简单、更干净。

添加 requirements.txt。

在其中添加 requirements。

==x.x 用于指定包版本,如果未给出版本,则始终安装最新版本。

然后右键单击你的 v.e. 并选择 Install from requirements.txt。

一切就绪,可以开始工作了。

你也可以查看它将包文件转储到哪里。

单元测试

单元测试代码始终是个好主意。我们可以在项目中添加 Python 单元测试文件,并编写类似 C# 的单元测试,然后通过默认的 Test Explorer 运行它。

并编写单元测试以检查数据库连接。

test1.py

import unittest


from SecDataModule.secData import SecData


class Test_test1(unittest.TestCase):

    def test_A(self):

        jsonRows = []

        secData = SecData("FromUnitTest")

        jsonRows = secData.getData("Test2")

        self.assertIsNotNone(jsonRows)


if __name__ == '__main__':

    unittest.main()

 

运行测试。

下载 PCC.DataAPI.zip

TODO

还有很多工作要做,但我在此停下。设置完成,基本代码已运行,轮子正在朝着正确的方向滚动。我相信任何有经验的 .NET 开发者都可以继续下去。

感谢您的阅读,如果您有任何问题,请随时提出(我可以处理 .22LR,但还没有准备好应对马格南弹药 J)。

值得关注的点  

参考

Python 官方教程
https://docs.pythonlang.cn/3.7/tutorial/index.html

Falcon
https://falconframework.org

VS 2017 - Python
https://docs.microsoft.com/en-us/visualstudio/python/managing-python-environments-in-visual-studio

历史

在此处保持您所做的任何更改或改进的实时更新。

© . All rights reserved.