Python如何实现链式属性调用以支持嵌套组合名称并返回数据对象?
Absolutely, this is totally achievable in Python—great idea for a clean, expressive API! The core issue with your original code is that __getattr__ returns a plain function, which doesn't support further attribute access. Instead, we need to return a chainable object that can both accumulate attribute names and trigger your printer method when called.
Here's a modified version of your code that implements this behavior:
class ChainableCall: def __init__(self, parent_printer, current_name): self.parent_printer = parent_printer self.current_name = current_name def __call__(self, *args, **kwargs): # When the chain is called (e.g., stack.echo()), trigger the printer method return self.parent_printer.printer(self.current_name, *args, **kwargs) def __getattr__(self, attr: str): # When an attribute is accessed (e.g., stack.echo.fail), extend the name chain return ChainableCall(self.parent_printer, f"{self.current_name}.{attr}") class Printer(): def __init__(self): pass def __getattr__(self, attr: str): # Return a chainable object starting with the first attribute name return ChainableCall(self, attr) def printer(self, name, *args, **kwargs): print(f'Name:{name}\nArguments:{args}\nKeys:{kwargs}') # In your actual project, replace the print with return your custom object here # Test it out stack = Printer() stack.echo('test', special=True) stack.echo.fail('test', special=True) stack.echo.fail.pass_('test', special=True) # Using pass_ since 'pass' is a Python keyword
Key Concepts Explained
Let's break down why this works, since you're still building your Python skills:
ChainableCallHelper Class: This is the magic piece. It holds two things: a reference to your originalPrinterinstance, and the accumulated name chain (like"echo"or"echo.fail").__call__: This special method lets the object behave like a function. When you add()to the end of the chain, this method triggers yourprintermethod with the full accumulated name.__getattr__: This catches any attribute access on theChainableCallobject. It creates a newChainableCallinstance with the extended name chain (e.g.,"echo"becomes"echo.fail").
- Modified
Printer.__getattr__: Instead of returning a plain function, it returns aChainableCallinstance starting with the first attribute name (like"echo").
Adapting to Your Actual Project
Since you mentioned your real printer-equivalent method returns a custom object, you don't need to change much: just replace the print statement in Printer.printer() with return your_custom_object(...). The ChainableCall.__call__ method will automatically return that object when the chain is called.
Notes for Your Python Journey
This uses two fundamental Python special methods (__getattr__ and __call__) that are super useful for building flexible APIs. Even though you've only been coding Python for 6 months, this is a great project to deepen your understanding of how objects behave in Python—you've already got the right intuition by experimenting with __getattr__!
内容的提问来源于stack exchange,提问作者volitank

