如何在Python类中动态创建带@task装饰器的50个自定义函数?
Got it, let's solve this problem of dynamically generating 50 methods in your class with custom names and URLs. The key issue you ran into is that regular function builders inside the class don't properly handle the self parameter—here's a straightforward, working approach:
Approach 1: Dynamically Add Methods After Class Definition
We can define your base class first, then loop through the 50 items to create each method, decorate it with @task(1), and attach it directly to the class using setattr. This ensures self is properly bound as a class method parameter.
import os # Import your task decorator from wherever it's defined from your_module import task class ItemViewer: def __init__(self, client): self.client = client # Ensure your class has the client attribute # Generate and attach 50 methods to the class for item_nr in range(1, 51): # Define the method with self parameter, using a default arg to capture the current item_nr @task(1) def view_item(self, item_nr=item_nr): self.client.get( url=f"/my-url/id=SEPT24_00{item_nr}", verify=False, auth=(os.environ['USERNAME'], os.environ['PASSWORD']) ) # Set the correct method name (critical for identifying the method later) method_name = f"view_item_with_id_{item_nr}" view_item.__name__ = method_name # Attach the method to the class setattr(ItemViewer, method_name, view_item)
Approach 2: Use a Class Decorator (Cleaner Encapsulation)
If you prefer to keep the generation logic tied to the class definition, a class decorator wraps the dynamic method creation neatly:
import os from your_module import task def add_item_view_methods(cls): """Class decorator to add 50 view_item_with_id_* methods""" for item_nr in range(1, 51): @task(1) def view_item(self, item_nr=item_nr): self.client.get( url=f"/my-url/id=SEPT24_00{item_nr}", verify=False, auth=(os.environ['USERNAME'], os.environ['PASSWORD']) ) method_name = f"view_item_with_id_{item_nr}" view_item.__name__ = method_name setattr(cls, method_name, view_item) return cls @add_item_view_methods class ItemViewer: def __init__(self, client): self.client = client
Key Details to Note:
- Capturing
item_nrCorrectly: We useitem_nr=item_nras a default parameter in the method definition. This avoids the common closure pitfall where all methods would use the final value ofitem_nrfrom the loop (due to late binding). - Method Naming: We explicitly set
__name__on each generated method so the methods have meaningful names (useful for debugging, logging, or test runners that rely on method names). selfBinding: By attaching the functions directly to the class viasetattr, they become proper instance methods—when you callinstance.view_item_with_id_1(), Python automatically passes the instance as theselfparameter.
Why Your Original Function Builder Didn't Work:
The function builder approach you tried creates standalone functions that aren't bound to the class's namespace. Without attaching them to the class, Python can't inject the self parameter automatically when the method is called on an instance. Our approach solves this by explicitly adding each function as a class attribute, making it a proper instance method.
内容的提问来源于stack exchange,提问作者D_Asti

