20、Python编程中的数据库、网络、文件格式与类定义

Python编程中的数据库、网络、文件格式与类定义

1. 使用对象关系映射

许多流行的SQL数据库都提供了Python驱动程序,但不同数据库的支持程度有所差异。在使用SQL数据库时,找到有效且可移植的SQL语法并非易事,因为某个数据库的特性在另一个数据库中可能会引发问题。

更重要的是,SQL表的扁平列行结构与Python等面向对象语言中复杂类定义的需求之间存在不匹配,这种阻抗不匹配通常可以通过对象关系映射(ORM)包来解决,常见的有SQLAlchemy和SQLObject。这些包有助于将复杂对象映射到简单的SQL表,还能使应用程序编程与特定SQL数据库的细节分离。

非SQL数据库,如 shelve 、MongoDB、CouchDB等NoSQL数据库,不存在SQL数据库那样的对象关系阻抗不匹配问题。Python可以与多种数据库配合使用,为持久化技术提供了丰富的选择。

2. 网络服务和互联网协议

许多TCP/IP协议(如HTTP)依赖于套接字抽象。套接字设计得像文件一样,我们可以使用普通的文件操作来读写套接字。在底层,我们可以使用Python的 socket 模块来创建、读写套接字,以连接客户端和服务器程序。

不过,我们通常会使用更高级的模块,如 urllib http.client ,它们提供了HTTP协议的客户端操作,使我们能够连接到Web服务器、发起请求并获取响应。要实现服务器,可以使用 http.server 。在实践中,我们常借助前端应用程序(如Apache HTTPD或NGINX)来提供网站的静态内容,对于动态内容,则使用WSGI网关将Web请求从前端传递到Python框架。Python有多个Web服务器框架,各有特点、优势和劣势。

3. 物理文件格式处理

Python库提供了许多模块来处理常见的物理文件格式:
- 文件压缩和归档:可处理使用zip或BZip2压缩的文件。
- 加密服务:处理CSV、配置文件和PLIST文件等格式。
- 结构化标记处理工具:处理JSON等互联网数据格式。
- 互联网协议和支持:处理HTML和XML等标记语言。

对于非标准库中的模块,可以在Python Package Index(PyPI)中查找处理特定文件格式的包。

下面重点介绍CSV模块,它在处理“大数据”问题时经常被使用。例如,Apache Hadoop软件库允许对大型数据集进行分布式处理,它采用简单的编程模型,我们可以使用Python进行Hadoop流式处理。Hadoop文件通常是CSV格式,分隔符可能是“|”或 \x01 (ASCII SOH)字符,使用Python的CSV模块可以轻松处理。

当从电子表格创建CSV文件时,第一行可能包含标题信息, csv.DictReader() 类会将第一行作为标题,将其余行转换为字典,字典的键就是第一行的列名。如果CSV文件没有标题行,则需要单独定义模式来确定每列的含义,通常可以用列名列表或元组来表示。例如:

TEST_LOG_SUMMARY = (
    "module", "datetime", "tests_run", "failures",
    "errors", "skipped", "time_elapsed",
)

我们可以将这个模式定义放在文件中并导入使用。

假设我们有一个 log_parser() 函数,它可以解析复杂的日志文件,提取所需字段,并使用 TEST_LOG_SUMMARY 中的键构建简单的字典。以下是使用该函数将日志内容写入CSV摘要文件的 mapper() 函数:

import csv
import glob
import sys

def mapper(name_iter, result):
    writer = csv.DictWriter(result, fieldnames=TEST_LOG_SUMMARY, delimiter='|')
    for name in name_iter:
        with open(name) as source:
            writer.writerow(log_parser(source))

# 示例调用
mapper(glob.glob("Chapter_10/log_*.txt"), sys.stdout)

这个函数接受一个生成日志文件名的迭代器和一个用于写入结果的打开文件作为参数。它会为每个日志文件调用 log_parser() 函数,并将解析结果写入CSV文件。我们将输出写入操作系统的标准输出,这样可以将结果通过管道传递给另一个计算日志摘要统计信息的程序,这个统计摘要程序可以称为reducer,它会共享 TEST_LOG_SUMMARY 变量,以确保两个程序对传递的文件内容达成一致。

4. 类定义基础

Python对象是类的实例,类通过方法函数定义对象的行为。下面介绍创建自定义类和对象的基础知识。

4.1 创建类

类定义是面向对象程序的核心,使用 class 语句创建一个用于创建类实例的对象。例如,创建一个新类 SomeClass 后,就可以使用 SomeClass() 函数创建共享该类定义的对象,就像内置类 int() 创建 int 类的实例一样。

在Python中, class 语句包含描述每个实例行为的方法函数,除了普通方法,还有一些与Python操作密切相关的“特殊”方法。我们不需要正式定义类的特定属性(实例变量),对象的实例变量是灵活的,无需提前定义。

class 语句的初始子句提供类名,还可以指定继承的超类,类体的主体包含使用缩进的 def 语句创建的方法定义。例如,创建一个自定义异常类:

class MyAppError(Exception):
    pass

这里定义了一个新的异常类 MyAppError ,它继承了 Exception 类的特性,由于不需要对基定义进行修改,使用 pass 语句完成类语句的语法。我们可以使用 raise MyAppError("Some Message") 来抛出这个新类的异常实例。

4.2 编写类中的语句组

类语句中的语句组通常是方法定义的集合,每个方法是绑定到类的函数。语句组还可以包含赋值语句,用于创建作为类定义一部分的变量。

以下是一个表示平面上(x, y)坐标对的简单类:

class Point:
    """
    Point on a plane.
    """
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return "{cls}({x:.0f}, {y:.0f})".format(
            cls=self.__class__.__name__, x=self.x, y=self.y)
  • 这个类名为 Point ,默认是 object 的子类。按照惯例,大多数内置类名以小写字母开头,自定义类名以大写字母开头。
  • 定义了两个方法:
  • __init__() :这是一个特殊方法,用于初始化对象的实例变量。第一个参数通常是 self ,它是对相关对象的引用。当为 self.x 赋值时,会设置 Point 类特定实例的 x 属性。
  • __repr__() :也是一个特殊方法,必须返回一个表示坐标对的字符串。如果不重写这个方法,将得到默认的字符串表示。我们的实现使用 self.__class__.__name__ 确保任何子类都能正确插入类名。

特殊方法名在Python中很常见,使用它们可以使我们的类与Python内置特性无缝集成。所有特殊方法名以双下划线 __ 开头和结尾,这种命名约定可以避免冲突。

我们可以这样创建类的实例:

p_1 = Point(22, 7)
print(p_1.x)  # 输出: 22
print(p_1.y)  # 输出: 7

当打印对象时,会调用内置的 repr() 函数,它依赖于对象的 __repr__() 方法来获取字符串表示:

print(p_1)  # 输出: Point(22, 7)
4.3 使用实例变量和方法

Point 类中添加一个非特殊方法 dist() ,用于计算平面上两点之间的直接距离:

import math

class Point:
    """
    Point on a plane.
    """
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return "{cls}({x:.0f}, {y:.0f})".format(
            cls=self.__class__.__name__, x=self.x, y=self.y)
    def dist(self, point):
        return math.hypot(self.x - point.x, self.y - point.y)

使用示例:

p_1 = Point(22, 7)
p_2 = Point(20, 5)
print(round(p_1.dist(p_2), 4))  # 输出: 2.8284

当调用 p_1.dist(p_2) 时, p_1 对象会被赋值给 self 变量, p_2 对象会被赋值给 point 参数变量。

默认情况下,我们创建的对象是可变的。再添加一个方法 offset() ,用于改变 Point 对象的内部状态:

class Point:
    """
    Point on a plane.
    """
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __repr__(self):
        return "{cls}({x:.0f}, {y:.0f})".format(
            cls=self.__class__.__name__, x=self.x, y=self.y)
    def dist(self, point):
        return math.hypot(self.x - point.x, self.y - point.y)
    def offset(self, d_x, d_y):
        self.x += d_x
        self.y += d_y

使用示例:

p_1 = Point(22, 7)
p_1.offset(-3, 3)
print(p_1.x)  # 输出: 19
print(p_1.y)  # 输出: 10
4.4 Python风格的面向对象编程

Python的面向对象编程有几个重要特点,其中最重要的是Python缺乏变量名和类型之间的静态绑定,任何类型的对象都可以赋值给任何变量,名称解析是动态的,这使得我们的程序在类方面具有通用性。

当计算 obj.attribute obj.method() 时,分为两个步骤:首先解析名称,然后计算引用的属性或方法。名称解析时,会搜索多个命名空间:
1. 搜索 obj 实例的本地命名空间( obj.__dict__ ),属性名和值通常在对象自己的命名空间中,而方法通常不在对象实例中。
2. 如果名称不在对象本地,搜索对象类的本地命名空间( obj.__class__.__dict__ ),方法名通常在类的命名空间中,类的属性也可能在此找到。
3. 如果名称不在类中,搜索超类,整个超类格会组装成 obj.__class__.__mro__ 值,定义了方法解析顺序(MRO),会按顺序搜索每个类。

一旦找到名称,Python会确定其值。对于非可调用方法的名称(即属性),名称引用的对象就是属性的值;对于可调用方法的名称,会绑定参数值并作为函数进行计算,函数的结果就是值。

这种搜索依赖于内置的 dict 类,使用哈希快速确定名称的存在与否,Python灵活的类行为带来的性能开销很小。如果在运行时提供了不适当类型的对象,对象中找不到方法名或属性名,会引发 AttributeError 异常。例如,尝试调用 p_1.copy() ,由于 copy 名称在类及其超类中未定义,会引发 AttributeError 异常。

总结

本文介绍了Python编程中数据库操作、网络服务、文件格式处理以及类定义的相关知识。在数据库方面,了解了对象关系映射解决SQL数据库阻抗不匹配的方法;网络服务中,掌握了使用高级模块进行HTTP操作和服务器实现的要点;文件格式处理涵盖了多种常见格式及CSV文件的详细处理;类定义部分则深入探讨了创建自定义类、使用实例变量和方法以及Python面向对象编程的特点。通过这些知识,我们可以更好地利用Python进行各种编程任务。

下面是一个简单的mermaid流程图,展示 Point 类方法调用的流程:

graph TD;
    A[创建Point对象p_1和p_2] --> B[调用p_1.dist(p_2)];
    B --> C{p_1赋值给self, p_2赋值给point};
    C --> D[计算两点距离];
    D --> E[返回距离值];
    A --> F[调用p_1.offset(-3, 3)];
    F --> G{p_1赋值给self};
    G --> H[更新p_1的x和y坐标];

同时,为了更清晰地展示不同模块的功能,我们可以列出一个表格:
| 模块类型 | 功能描述 |
| ---- | ---- |
| 数据库ORM | 解决SQL数据库阻抗不匹配,映射对象到SQL表 |
| 网络模块 | 提供HTTP客户端和服务器操作 |
| 文件处理模块 | 处理各种物理文件格式 |
| 自定义类 | 定义对象行为,实现面向对象编程 |

Python编程中的数据库、网络、文件格式与类定义

5. 数据库操作深入探讨

在数据库操作中,SQL数据库和非SQL数据库各有特点。SQL数据库虽然功能强大,但存在对象关系阻抗不匹配的问题,而对象关系映射(ORM)包如SQLAlchemy和SQLObject可以很好地解决这个问题。以下是使用ORM进行数据库操作的一般步骤:
1. 安装ORM包 :可以使用 pip install sqlalchemy pip install sqlobject 进行安装。
2. 连接数据库 :以SQLAlchemy为例,代码如下:

from sqlalchemy import create_engine

# 连接到SQLite数据库
engine = create_engine('sqlite:///example.db')
  1. 定义模型类
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    age = Column(Integer)
  1. 创建表
Base.metadata.create_all(engine)
  1. 插入数据
from sqlalchemy.orm import sessionmaker

Session = sessionmaker(bind=engine)
session = Session()

new_user = User(name='John', age=25)
session.add(new_user)
session.commit()
  1. 查询数据
users = session.query(User).all()
for user in users:
    print(user.name, user.age)

非SQL数据库如MongoDB、CouchDB等则不存在对象关系阻抗不匹配的问题。以MongoDB为例,使用Python进行操作的步骤如下:
1. 安装驱动 :使用 pip install pymongo 进行安装。
2. 连接数据库

from pymongo import MongoClient

client = MongoClient('mongodb://localhost:27017/')
db = client['test_database']
collection = db['test_collection']
  1. 插入数据
document = {'name': 'Alice', 'age': 30}
collection.insert_one(document)
  1. 查询数据
results = collection.find()
for result in results:
    print(result)
6. 网络编程实践

在网络编程中,使用高级模块可以更方便地进行HTTP操作。下面是一个使用 http.client 模块发送HTTP请求的示例:

import http.client

conn = http.client.HTTPSConnection("www.example.com")
conn.request("GET", "/")
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
conn.close()

如果要实现一个简单的HTTP服务器,可以使用 http.server 模块:

import http.server
import socketserver

PORT = 8000

Handler = http.server.SimpleHTTPRequestHandler

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    print(f"Serving at port {PORT}")
    httpd.serve_forever()

在实际应用中,通常会使用前端应用程序(如Apache HTTPD或NGINX)来提供静态内容,使用WSGI网关将动态请求传递给Python框架。常见的Python Web服务器框架有Flask、Django等。以Flask为例,创建一个简单的Web应用的步骤如下:
1. 安装Flask :使用 pip install flask 进行安装。
2. 创建应用

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run()
7. 文件格式处理拓展

除了CSV文件,Python还可以处理多种其他文件格式。以下是一些常见文件格式的处理示例:
- JSON文件

import json

# 写入JSON文件
data = {'name': 'Bob', 'age': 35}
with open('data.json', 'w') as f:
    json.dump(data, f)

# 读取JSON文件
with open('data.json', 'r') as f:
    loaded_data = json.load(f)
    print(loaded_data)
  • XML文件
import xml.etree.ElementTree as ET

# 创建XML元素
root = ET.Element('root')
child = ET.SubElement(root, 'child')
child.text = 'Hello, XML!'

# 写入XML文件
tree = ET.ElementTree(root)
tree.write('data.xml')

# 读取XML文件
tree = ET.parse('data.xml')
root = tree.getroot()
for child in root:
    print(child.text)
  • 压缩文件
import zipfile

# 创建压缩文件
with zipfile.ZipFile('archive.zip', 'w') as zipf:
    zipf.write('data.json')

# 解压压缩文件
with zipfile.ZipFile('archive.zip', 'r') as zipf:
    zipf.extractall()
8. 类定义的高级特性

在类定义中,除了前面介绍的基本内容,还有一些高级特性,如类方法和静态方法。
- 类方法 :使用 @classmethod 装饰器定义,第一个参数是类本身,通常命名为 cls 。类方法可以访问类的属性和调用类的其他方法。

class MyClass:
    class_variable = 10

    @classmethod
    def class_method(cls):
        print(f"Class variable: {cls.class_variable}")

MyClass.class_method()
  • 静态方法 :使用 @staticmethod 装饰器定义,不需要特定的第一个参数。静态方法与类和实例没有直接关系,只是逻辑上属于类的一部分。
class MyClass:
    @staticmethod
    def static_method():
        print("This is a static method.")

MyClass.static_method()

另外,Python还有内置的抽象基类,我们可以使用它们来简化自定义类的定义。例如, collections.abc 模块中的抽象基类可以帮助我们创建容器类。

from collections.abc import Sequence

class MySequence(Sequence):
    def __init__(self, data):
        self.data = data

    def __len__(self):
        return len(self.data)

    def __getitem__(self, index):
        return self.data[index]

seq = MySequence([1, 2, 3])
print(len(seq))
print(seq[1])
总结

本文进一步深入探讨了Python编程中数据库操作、网络编程、文件格式处理和类定义的高级特性。在数据库操作方面,详细介绍了SQL数据库和非SQL数据库的使用方法;网络编程中,提供了HTTP请求发送和服务器实现的示例以及常见Web框架的使用;文件格式处理拓展到了JSON、XML和压缩文件;类定义的高级特性包括类方法、静态方法和抽象基类的使用。通过这些知识,我们可以更全面地掌握Python编程,应对更复杂的编程任务。

下面是一个表格,总结不同编程领域的关键知识点:
| 编程领域 | 关键知识点 |
| ---- | ---- |
| 数据库操作 | ORM包使用、SQL和非SQL数据库连接与操作 |
| 网络编程 | 高级模块HTTP操作、服务器实现、Web框架使用 |
| 文件格式处理 | CSV、JSON、XML、压缩文件处理 |
| 类定义 | 类方法、静态方法、抽象基类使用 |

以下是一个mermaid流程图,展示文件处理的一般流程:

graph TD;
    A[选择文件格式] --> B{CSV文件};
    B -- 是 --> C[使用CSV模块处理];
    B -- 否 --> D{JSON文件};
    D -- 是 --> E[使用json模块处理];
    D -- 否 --> F{XML文件};
    F -- 是 --> G[使用xml.etree.ElementTree模块处理];
    F -- 否 --> H{压缩文件};
    H -- 是 --> I[使用zipfile模块处理];
    H -- 否 --> J[其他格式待处理];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值