Python | class 实例化前的方法装饰器
Python | class method decorator before instantiation
前言:这个问题可能比标题所暗示的要简单
我正在尝试实现一个简单的事件处理程序系统,使用装饰器 'subscribe' 事件的各种方法和函数。
1。事件处理程序的简单方法
一个简单的方法是创建一个 class 用于添加和 运行 事件:
# 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'
显然这里的问题是我在事件中添加 'static'(或者是 'unbound'?)myMethod
,它与实例无关,因此没有 self
.
的任何实例
诸如 this 之类的答案是指实现装饰器来包装方法 as 它们被调用,但是我的原因使用装饰器是您在初始代码执行时获得的访问权限。
一个想法是在 MyClass.__init__()
构造函数中必须 运行,因为只有这样才会创建一个实例并且您可以访问 self
,但是如何你 运行 装饰器 only 实例化吗?更不用说达到我们想要的结果了。
问题
我有什么选择来实现示例 1 中所示的行为,但语法尽可能接近示例 2(或任何其他 'clean looking' 变体),因为 runner.add()
有点冗长,丑陋,肯定没有装饰器那么精简。
干杯!
函数和方法的处理方式略有不同,而不是一视同仁:
函数:
[A]
正常添加函数到列表
方法:
- 调用装饰器时的未绑定方法,因此
self
还没有关联的实例或值
[B]
我们 'tag' 通过设置其 _tagged
属性 'tag' 未绑定方法(在创建实例之前) 43=]
[C]
创建实例后(并且 self
变量已填充),我们在 __init__()
中搜索并添加所有标记的方法
- 我们可以在之后添加这些方法,因为一旦它们绑定到一个实例,
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()
前言:这个问题可能比标题所暗示的要简单
我正在尝试实现一个简单的事件处理程序系统,使用装饰器 'subscribe' 事件的各种方法和函数。
1。事件处理程序的简单方法
一个简单的方法是创建一个 class 用于添加和 运行 事件:
# 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'
显然这里的问题是我在事件中添加 'static'(或者是 'unbound'?)myMethod
,它与实例无关,因此没有 self
.
诸如 this 之类的答案是指实现装饰器来包装方法 as 它们被调用,但是我的原因使用装饰器是您在初始代码执行时获得的访问权限。
一个想法是在 MyClass.__init__()
构造函数中必须 运行,因为只有这样才会创建一个实例并且您可以访问 self
,但是如何你 运行 装饰器 only 实例化吗?更不用说达到我们想要的结果了。
问题
我有什么选择来实现示例 1 中所示的行为,但语法尽可能接近示例 2(或任何其他 'clean looking' 变体),因为 runner.add()
有点冗长,丑陋,肯定没有装饰器那么精简。
干杯!
函数和方法的处理方式略有不同,而不是一视同仁:
函数:
[A]
正常添加函数到列表
方法:
- 调用装饰器时的未绑定方法,因此
self
还没有关联的实例或值 [B]
我们 'tag' 通过设置其_tagged
属性 'tag' 未绑定方法(在创建实例之前) 43=][C]
创建实例后(并且self
变量已填充),我们在__init__()
中搜索并添加所有标记的方法- 我们可以在之后添加这些方法,因为一旦它们绑定到一个实例,
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()