我正在尝试创建一个实例化串行对象的类(MySerial
),以便我可以写入/读取串行设备(UART)。有一个实例方法是一个装饰器,它包含一个属于完全不同的类(App
)的函数。因此装饰器负责写入和读取串行缓冲区。
如果我在MySerial
类中创建App
的实例,我就无法使用从MySerial
创建的装饰器实例方法。
我已经尝试过前面的实例方法并使用this second answer中解释的类方法,但我确实需要实例化MySerial
,因此使用__init__
创建一个实例。
如何实现这一目标?这不可能吗?
class MySerial():
def __init__(self):
pass # I have to have an __init__
def write(self):
pass # write to buffer
def read(self):
pass # read to buffer
def decorator(self, func):
def func_wrap(*args, **kwargs):
self.write(func(*args, **kwars))
return self.read()
return func_wrap
class App():
def __init__(self):
self.ser = MySerial()
@self.ser.decorator # <-- does not work here.
def myfunc(self):
# 'yummy_bytes' is written to the serial buffer via
# MySerial's decorator method
return 'yummy_bytes'
if __name__ == '__main__':
app = App()
答案 0 :(得分:1)
您可以使用staticmethod
打包decorator
。 func_wrap
的内部decorator
函数在其签名中包含一个附加参数:cls
。 cls
可用于访问ser
实例的App
属性,然后可以从{{1}调用所需的方法write
和read
}}。另请注意,在您的声明中,cls.ser
不接受参数,但会传递包装函数的结果。以下代码使用MySerial.write
来阻止原本会被引发的*args
:
TypeError
答案 1 :(得分:1)
这不起作用的原因是因为你在类体中引用了self
,它没有定义。这是两个解决方案。
如果您将MySerial
实例存储为类属性,则可以在类主体中访问它:
class App():
ser = MySerial()
@ser.decorator
def myfunc(self):
return 'yummy_bytes'
或者,如果每个MySerial
实例需要不同的App
实例,则需要等待创建实例以定义实例属性{{ 1}}。这意味着函数在每个实例创建时动态修饰,在这种情况下,my_func
装饰器语法必须由函数调用替换。
@
此解决方案概括为装饰多种方法或有条件地停用序列化,例如在测试环境中。
class App():
def __init__(self):
self.ser = MySerial()
self.my_func = self.ser.decorator(self.myfunc)
def myfunc(self):
return 'yummy_bytes'
答案 2 :(得分:0)
有很多隐藏的陷阱使这个设计变得有风险,但这是一个很好的学习范例。
首先,装饰时对'self'的调用失败,因为在该范围内没有自我。它只存在于方法中。现在,简单的一个就不在了......
myfunc是App类的一个属性。当您创建App的实例时,始终会调用一个函数。即使它变得有条理,也只会发生一次。
a1 = App()
a2 = App()
assert a1.myfunc.__func__ is a2.myfunc.__func__
assert id(a1.myfunc) is id(a2.myfunc) # Methods have some weirdness that means that won't equate but id's show they are the same
这就是为什么需要self来为实例获取唯一的命名空间。这也是为什么你不能以这种方式获得实例独有的装饰器的原因。 考虑它的另一种方法是必须在生成实例之前定义Class。因此,您无法在类的定义中使用实例。
装饰器需要以不存储任何实例属性的方式编写。它将改为访问App实例属性。
class MySerial():
def __init__(self):
pass # Possibly don't need to have an __init__
def write(self, serial_config):
pass # write to buffer
def read(self, serial_config):
pass # read to buffer
def decorator(self, func):
def func_wrap(self_app: App, *args, **kwargs):
self.write(func(self_app, *args, **kwars), self_app.serial_config)
return self.read(self_app.serial_config)
return func_wrap
ser = MySerial()
class App():
def __init__(self, serial_config):
self.serial_config = serial_config # This is the instance data for MySerial
@ser.decorator
def myfunc(self):
# 'yummy_bytes' is written to the serial buffer via
# MySerial's decorator method
return 'yummy_bytes'
if __name__ == '__main__':
app = App()
现在我假设MySerial将有一个唯一的文件,或端口或每个App实例的东西。这是将在serial_config中记录的内容。如果流正在打开结束时,这可能不是很优雅,但您应该能够针对您的确切应用进行改进。