gpt4 book ai didi

python |实例化前的类方法装饰器

转载 作者:行者123 更新时间:2023-12-05 07:03:00 24 4
gpt4 key购买 nike

前言:这个问题可能比标题所暗示的要简单

我正在尝试实现一个简单的事件处理程序系统,使用装饰器将各种方法和函数“订阅”到一个事件。


1。事件处理程序的简单方法

一个简单的方法是创建一个类来添加和运行事件:

# class for adding and running functions, aka an event handler
class Runner:
def __init__(self):
self.functions = []
def add(self, function):
self.functions.append(function)
def run(self):
for function in self.functions:
function()

runner = Runner()

然后添加各种函数或方法:

# random example function
def myFunction():
print('myFunction')

# random example class
class MyClass:
def myMethod(self):
print('myMethod')

# getting instance of class & method
myObject = MyClass()
myObjectMethod = myObject.myMethod

runner.add(myFunction)
runner.add(myObjectMethod)
runner.run()

这导致:

> py main.py
myFunction
myMethod

不错!它按预期工作


2。装饰器方法

所以这没关系,但我最近了解了装饰器,并认为我可以通过替换有点丑陋的 runner.add() 方法来整理语法。

首先,我将 Runner.add() 方法更改为装饰器:

class Runner:
def __init__(self):
self.functions = []
def add(self, function):
self.functions.append(function)
return function # <-- returns function
def run(self):
for function in self.functions:
function()

runner = Runner()

然后我删除 runner.add() 调用并插入装饰器:

@runner.add
def myFunction():
print('myFunction')

class MyClass:
@runner.add
def myMethod(self):
print('myMethod')

# myObject = MyClass()
# myObjectMethod = myObject.myMethod

runner.run()

这显然会导致:

> py main.py
myFunction
Traceback (most recent call last):
...
TypeError: myMethod() missing 1 required positional argument: 'self'

很明显,这里的问题是我将“静态”(或者它是“未绑定(bind)”?)myMethod 添加到事件中,该事件没有关联有一个实例,因此没有 self 的任何实例。

诸如 this 之类的答案一个是指实现装饰器以包装方法它们被调用,但我使用装饰器的原因是您在初始代码执行时获得的访问权限。

一个想法是必须在 MyClass.__init__() 构造函数中运行一些东西,因为只有这样才会创建一个实例并且您可以访问 self,但是如何在实例化时 运行装饰器?更不用说实现我们在这里追求的结果了。


问题

由于runner.add() 有点冗长、丑陋,而且肯定不像装饰器那样精简。

干杯!

最佳答案

不是以相同的方式对待函数和方法,而是以稍微不同的方式处理它们:

功能:

  • [A] 正常添加函数到列表

方法:

  • 调用装饰器时未绑定(bind)的方法,因此 self 还没有关联的实例或值
  • [B] 我们通过设置其 _tagged 属性,在方法未绑定(bind)时(在创建实例之前)“标记”该方法/li>
  • [C] 创建实例后(并且填充了 self 变量),在 __init__() 中 我们搜索并添加所有标记的方法
  • 我们可以在之后添加这些方法,因为一旦它们绑定(bind)到一个实例,self 参数就会被填充(这意味着它在技术上没有参数,类似于 functools.partial())
import inspect

class Runner:
def __init__(self):
self.functions = []

def add(self, function):
if len(inspect.signature(function).parameters) == 0:
# [A] adds if has no parameters
self.functions.append(function)
else:
# [B] tags if has 1 parameter (unbound methods have "self" arg)
function._tagged = True
return function

# [C] search through object and add all tagged methods
def add_all_tagged_methods(self, object):
for method_name in dir(object):
method = getattr(object, method_name)
if hasattr(method, '_tagged'):
self.functions.append(method)

def run(self):
for function in self.functions:
function()

runner = Runner()

然后使用与下面相同的初始代码

@runner.add
def myFunction():
print('myFunction')

class MyClass:
def __init__(self):
runner.add_all_tagged_methods(self)

@runner.add
def myMethod(self):
print('myMethod')

myObject = MyClass()
myObjectMethod = myObject.myMethod

runner.run()

关于 python |实例化前的类方法装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63396641/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com