杰瑞科技汇

Python 模式设计有哪些常见类型?

Of course! The term "pattern" in Python can refer to several different things. I'll cover the most common ones, from fundamental programming concepts to advanced design techniques.

Python 模式设计有哪些常见类型?-图1
(图片来源网络,侵删)

Fundamental Programming Patterns (Syntax & Idioms)

These are recurring structures and idioms you'll see constantly in Python code.

a) String Formatting (Pattern for Embedding Variables in Strings)

There are three main ways to do this, with the third being the modern standard.

Old Style Formatting ( operator) The original C-style formatting.

name = "Alice"
age = 30
print("Hello, my name is %s and I am %d years old." % (name, age))

str.format() Method More flexible and readable than the old style.

Python 模式设计有哪些常见类型?-图2
(图片来源网络,侵删)
name = "Bob"
age = 25
print("Hello, my name is {} and I am {} years old.".format(name, age))
# You can also use positional or keyword arguments
print("Hello, my name is {n} and I am {a} years old.".format(n=name, a=age))

f-Strings (Formatted String Literals) - RECOMMENDED**** Introduced in Python 3.6, f-strings are the most popular, concise, and readable way. They are evaluated at runtime.

name = "Charlie"
age = 35
print(f"Hello, my name is {name} and I am {age} years old.")
# You can even embed expressions!
print(f"Next year, I will be {age + 1} years old.")

b) Looping Patterns (Iterating Over Collections)

Iterating Over a List/Tuple (Standard for loop) This is the most common pattern.

fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

Iterating with an Index (enumerate) When you need both the item and its index.

fruits = ["apple", "banana", "cherry"]
for index, fruit in enumerate(fruits):
    print(f"Index {index}: {fruit}")

Iterating Over a Dictionary By default, iterating over a dictionary gives you its keys.

Python 模式设计有哪些常见类型?-图3
(图片来源网络,侵删)
person = {"name": "David", "city": "New York"}
for key in person:
    print(key)
# To get key-value pairs:
for key, value in person.items():
    print(f"{key}: {value}")

Iterating Over a List with Index and Value (enumerate with start) A more explicit version of the enumerate pattern.

fruits = ["apple", "banana", "cherry"]
for i in range(len(fruits)):
    print(f"Index {i}: {fruits[i]}")
# The enumerate() version is generally preferred for its clarity.

c) Conditional Patterns

if-elif-else Chain For handling multiple, mutually exclusive conditions.

score = 85
if score >= 90:
    grade = 'A'
elif score >= 80:
    grade = 'B'
elif score >= 70:
    grade = 'C'
else:
    grade = 'F'
print(f"Grade: {grade}")

Ternary Operator (Conditional Expression) A one-line if-else statement for simple assignments.

age = 20
status = "Adult" if age >= 18 else "Minor"
print(status)

d) File Handling Pattern (The with statement)

This is the standard, safe way to handle files in Python. The with statement ensures that the file is automatically closed, even if errors occur.

# Recommended pattern
try:
    with open('my_file.txt', 'r') as f:
        content = f.read()
        print(content)
except FileNotFoundError:
    print("Error: The file was not found.")
# Old, less safe way (file might not be closed on error)
# f = open('my_file.txt', 'r')
# content = f.read()
# f.close() # Easy to forget this line

Design Patterns (Object-Oriented)

These are well-established, reusable solutions to common software design problems. Python's flexibility allows you to implement them in clean, "Pythonic" ways.

a) Singleton Pattern

Ensures a class has only one instance and provides a global point of access to it.

Pythonic Implementation: Using a module. Since a module is only imported once, its contents act as a natural singleton.

# database.py
class DatabaseConnection:
    _instance = None
    def __new__(cls):
        if cls._instance is None:
            print("Creating new database connection...")
            cls._instance = super(DatabaseConnection, cls).__new__(cls)
            # Initialize the connection here
        return cls._instance
    def query(self, sql):
        print(f"Executing query: {sql}")
# main.py
# from database import DatabaseConnection
# db1 = DatabaseConnection()
# db2 = DatabaseConnection()
# print(db1 is db2)  # Output: True
# db1.query("SELECT * FROM users")

b) Factory Pattern

Defines an interface for creating an object, but lets subclasses decide which class to instantiate. It promotes loose coupling.

Pythonic Implementation: Using a simple function that returns an instance of a class.

from enum import Enum
class PizzaType(Enum):
    MARGHERITA = "margherita"
    PEPPERONI = "pepperoni"
# --- Concrete Products ---
class MargheritaPizza:
    def prepare(self):
        return "Preparing Margherita Pizza"
class PepperoniPizza:
    def prepare(self):
        return "Preparing Pepperoni Pizza"
# --- The Factory ---
def pizza_factory(pizza_type: PizzaType):
    if pizza_type == PizzaType.MARGHERITA:
        return MargheritaPizza()
    elif pizza_type == PizzaType.PEPPERONI:
        return PepperoniPizza()
    else:
        raise ValueError("Unknown pizza type")
# --- Client Code ---
order1 = pizza_factory(PizzaType.MARGHERITA)
print(order1.prepare()) # Output: Preparing Margherita Pizza
order2 = pizza_factory(PizzaType.PEPPERONI)
print(order2.prepare()) # Output: Preparing Pepperoni Pizza

c) Observer Pattern

Defines a one-to-many dependency between objects. When one object (the subject) changes its state, all its dependents (observers) are notified.

Pythonic Implementation: Using Python's built-in Observer pattern from the abc module or a simple list of callbacks.

from abc import ABC, abstractmethod
# --- Observer Interface ---
class Observer(ABC):
    @abstractmethod
    def update(self, message: str):
        pass
# --- Concrete Observers ---
class UserEmailNotifier(Observer):
    def update(self, message: str):
        print(f"Sending email notification: {message}")
class MobileAppNotifier(Observer):
    def update(self, message: str):
        print(f"Sending push notification to app: {message}")
# --- Subject (the one being observed) ---
class NewsAgency:
    def __init__(self, name: str):
        self.name = name
        self._observers = []
        self._latest_news = None
    def attach(self, observer: Observer):
        if observer not in self._observers:
            self._observers.append(observer)
    def detach(self, observer: Observer):
        try:
            self._observers.remove(observer)
        except ValueError:
            pass
    def notify(self):
        for observer in self._observers:
            observer.update(self._latest_news)
    def add_news(self, news: str):
        print(f"\n{self.name} has new news!")
        self._latest_news = news
        self.notify()
# --- Client Code ---
news_agency = NewsAgency("Tech Times")
user1 = UserEmailNotifier()
app1 = MobileAppNotifier()
news_agency.attach(user1)
news_agency.attach(app1)
news_agency.add_news("New Python version released!")
news_agency.detach(user1)
news_agency.add_news("Design Patterns are important.")

Data Analysis Patterns (Pandas)

When working with data in pandas, certain patterns are essential for manipulating and analyzing data.

a) The Chain Pattern (Method Chaining)

Pandas is designed for method chaining, where you perform a series of operations on a DataFrame in a single, readable line.

import pandas as pd
# Sample data
data = {'Name': ['Alice', 'Bob', 'Charlie', 'David'],
        'Age': [25, 30, 35, 28],
        'City': ['New York', 'Los Angeles', 'Chicago', 'New York']}
df = pd.DataFrame(data)
# Pattern: Filter, then select, then sort
result = (df
          .query('Age > 26')           # Filter rows
          .loc[:, ['Name', 'City']]    # Select columns
          .sort_values(by='Name')      # Sort by a column
         )
print(result)

b) The Group-By-Aggregate Pattern

This is the cornerstone of data summarization. You split data into groups, apply a function, and combine the results.

# Sample sales data
sales_data = {'Product': ['A', 'B', 'A', 'C', 'B', 'A'],
              'Sales': [100, 150, 200, 50, 120, 180]}
sales_df = pd.DataFrame(sales_data)
# Pattern: Group by 'Product' and calculate total sales
total_sales_per_product = sales_df.groupby('Product')['Sales'].sum()
print(total_sales_per_product)

Summary Table

Category Pattern Name Pythonic Example Use Case
Fundamental String Formatting f"Hello, {name}" Embedding variables in strings.
Looping with Index for i, item in enumerate(my_list): Needing both index and value in a loop.
Safe File Handling with open('file.txt') as f: Ensuring resources are managed correctly.
Design (OOP) Singleton Module-level variables or a class with __new__. Ensuring only one instance of a class exists.
Factory def create_animal(animal_type): return Animal(...) Creating objects without specifying the exact class.
Observer A list of update methods that get called on change. Decoupling objects so one can notify many others.
Data Analysis Method Chaining df.query(...).loc[...].sort_values(...) Performing multiple DataFrame operations cleanly.
Group-By-Aggregate df.groupby('col').agg({'col2': 'sum'}) Summarizing data based on categories.
分享:
扫描分享到社交APP
上一篇
下一篇