杰瑞科技汇

_python中如何使用_format?_

Of course! Let's dive deep into the __format__ magic method in Python.

_python中如何使用_format?_-图1
(图片来源网络,侵删)

What is __format__?

The __format__ method is a special "dunder" (double underscore) method in Python that allows an object to control how it is formatted into a string. It's the underlying mechanism that powers the built-in format() function and the string formatting method using the format_spec mini-language (e.g., "{:,.2f}".format(12345.678)).

When you use format(my_object, format_spec), Python looks for the __format__ method on my_object. If it's defined, it calls my_object.__format__(format_spec).

The Core Concept: format_spec

The key to __format__ is the format_spec, or format specification. This is a string that tells the formatting engine how to present the object. It's the part inside the curly braces after the colon ().

For example, in "{:,.2f}".format(12345.678):

_python中如何使用_format?_-图2
(图片来源网络,侵删)
  • The object is 678.
  • The format_spec is ,.2f.

The standard built-in types (int, float, str, datetime, etc.) already have their own __format__ methods that understand a specific set of format specifications (like .2f for two decimal places, or d for integer).

Your custom __format__ method gives your objects the same power.


How to Implement __format__

The signature for the method is:

def __format__(self, format_spec: str) -> str:
    # ... your formatting logic ...
    return formatted_string
  • self: The instance of your class.
  • format_spec: A string containing the format specification.
  • Return Value: It must return a string.

A Simple Example: A Person Class

Let's create a Person class and let it format itself in different ways.

_python中如何使用_format?_-图3
(图片来源网络,侵删)
class Person:
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
    def __repr__(self):
        return f"Person('{self.first_name}', '{self.last_name}', {self.age})"
    def __format__(self, format_spec):
        print(f"__format__ called with format_spec: '{format_spec}'")
        if format_spec == "full":
            return f"{self.last_name}, {self.first_name} (Age: {self.age})"
        elif format_spec == "initials":
            return f"{self.first_name[0]}.{self.last_name[0]}."
        elif not format_spec: # Default formatting if no spec is given
            return f"{self.first_name} {self.last_name}"
        else:
            # If an unknown format spec is provided, raise an error
            raise ValueError(f"Unknown format specifier '{format_spec}' for object of type '{self.__class__.__name__}'")
# --- Usage ---
p = Person("John", "Doe", 30)
# 1. Using the format() function
print(f"Using format() function:")
print(format(p, "full"))
print(format(p, "initials"))
print(format(p)) # No format_spec provided
print("\n" + "="*20 + "\n")
# 2. Using f-strings (this is where it becomes powerful!)
print(f"Using f-strings:")
print(f"{p:full}")
print(f"{p:initials}")
print(f"{p}") # Default formatting
# This will raise a ValueError
try:
    print(f"{p:unknown_format}")
except ValueError as e:
    print(f"\nCaught expected error: {e}")

Output:

Using format() function:
__format__ called with format_spec: 'full'
Doe, John (Age: 30)
__format__ called with format_spec: 'initials'
J.D.
__format__ called with format_spec: ''
John Doe
====================
Using f-strings:
__format__ called with format_spec: 'full'
Doe, John (Age: 30)
__format__ called with format_spec: 'initials'
J.D.
__format__ called with format_spec: ''
John Doe
Caught expected error: Unknown format specifier 'unknown_format' for object of type 'Person'

As you can see, both format(p, "full") and f"{p:full}" trigger the exact same __format__ method, making your objects seamlessly integrate with Python's powerful string formatting tools.


Advanced Example: A Money Class with the Standard Format Spec

What if you want your custom object to use the standard format spec language, like ,.2f for currency? You can do this by parsing the format_spec string and delegating the formatting to a built-in type.

Let's create a Money class that stores an amount as a float but formats it as currency.

class Money:
    def __init__(self, amount: float, currency_symbol: str = "$"):
        self.amount = amount
        self.currency_symbol = currency_symbol
    def __format__(self, format_spec):
        # If no format_spec is given, we'll use a sensible default.
        if not format_spec:
            format_spec = ",.2f"
        # Use the float's own __format__ method to handle the numeric part.
        # This is the key to reusing the standard formatting!
        formatted_amount = format(self.amount, format_spec)
        return f"{self.currency_symbol}{formatted_amount}"
# --- Usage ---
price = Money(12345.6789)
print(f"Default: {price}")
print(f"With 0 decimal places: {price:,.0f}")
print(f"With 4 decimal places: {price:,.4f}")
print(f"In scientific notation: {price:.2e}")

Output:

Default: $12,345.68
With 0 decimal places: $12,346
With 4 decimal places: $12,345.6789
In scientific notation: $1.23e+04

In this example, our Money.__format__ method doesn't try to parse ,.2f itself. Instead, it passes the format_spec to the built-in float type's __format__ method (format(self.amount, format_spec)). This is a powerful pattern for composition.


Relationship to Other Formatting Methods

It's important to understand how __format__ fits in with other string representation methods:

Method Called By... Purpose Return Type
__str__ str(obj), print(obj), f"{obj}" (no spec) "User-friendly" or informal string representation. What the end-user sees. str
__repr__ repr(obj), f"{obj!r}" "Official" or developer-friendly representation. Should be valid Python code. str
__format__ format(obj, spec), f"{obj:spec}" Controlled, customizable formatting using a specification. str

Resolution Order (for f"{obj}"):

  1. If the object's class defines __format__, it is called with an empty format_spec ().
  2. If __format__ is not defined, Python falls back to using str(obj).
  3. If __format__ is defined but raises a TypeError, Python also falls back to str(obj).

This means if you define __format__, you are in control of f"{obj}" behavior unless you explicitly raise an error.

Summary

  • The __format__ method is the magic behind Python's advanced string formatting.
  • It allows your custom objects to be formatted using format() and, more importantly, f-strings with a format_spec.
  • The format_spec is a string that you define the meaning of (e.g., "full", "initials") or you can parse to delegate to built-in types (like float or int).
  • It makes your objects integrate seamlessly with Python's string formatting ecosystem, leading to cleaner, more readable, and more powerful code.
分享:
扫描分享到社交APP
上一篇
下一篇