Python class 装饰器 "self" 似乎不对
Python class decorator "self" seems wrong
我正在尝试弄清楚如何使用 class 上的装饰器更改 class 的 __setattr__
的功能,但我 运行 遇到了问题当试图在替换 __setattr__
的函数中访问 self
时。如果我将问题行更改为不访问 self
,例如用 val = str(val)
替换它,我得到了预期的行为。
我在这里的其他问题中看到类似的问题,但他们使用不同的方法,其中 class 用作装饰器。我下面的方法感觉不那么复杂,所以如果可能的话,我很乐意保持这样。
为什么 a
没有在我期望的 self
/foo
上定义?
# Define the function to be used as decorator
# The decorator function accepts the relevant fieldname as argument
# and returns the function that wraps the class
def field_proxied(field_name):
# wrapped accepts the class (type) and modifies the functionality of
# __setattr__ before returning the modified class (type)
def wrapped(wrapped_class):
super_setattr = wrapped_class.__setattr__
# The new __setattr__ implementation makes sure that given an int,
# the fieldname becomes a string of that int plus the int in the
# `a` attribute
def setattr(self, attrname, val):
if attrname == field_name and isinstance(val, int):
val = str(self.a + val) # <-- Crash. No attribute `a`
super_setattr(self, attrname, val)
wrapped_class.__setattr__ = setattr
return wrapped_class
return wrapped
@field_proxied("b")
class Foo(object):
def __init__(self):
self.a = 2
self.b = None
foo = Foo()
# <-- At this point, `foo` has no attribute `a`
foo.b = 4
assert foo.b == "6" # Became a string
问题很简单,改一行就可以了
def setattr(self, attrname, val):
if attrname == field_name and isinstance(val, int):
val = str(self.a + val)
super_setattr(self, attrname, val) # changed line
原因是,在你原来的方法中,你只会在attrname == field_name
时调用super_setattr
。所以 __init__
中的 self.a = 2
根本不起作用,因为 "a" != "b"
.
我正在尝试弄清楚如何使用 class 上的装饰器更改 class 的 __setattr__
的功能,但我 运行 遇到了问题当试图在替换 __setattr__
的函数中访问 self
时。如果我将问题行更改为不访问 self
,例如用 val = str(val)
替换它,我得到了预期的行为。
我在这里的其他问题中看到类似的问题,但他们使用不同的方法,其中 class 用作装饰器。我下面的方法感觉不那么复杂,所以如果可能的话,我很乐意保持这样。
为什么 a
没有在我期望的 self
/foo
上定义?
# Define the function to be used as decorator
# The decorator function accepts the relevant fieldname as argument
# and returns the function that wraps the class
def field_proxied(field_name):
# wrapped accepts the class (type) and modifies the functionality of
# __setattr__ before returning the modified class (type)
def wrapped(wrapped_class):
super_setattr = wrapped_class.__setattr__
# The new __setattr__ implementation makes sure that given an int,
# the fieldname becomes a string of that int plus the int in the
# `a` attribute
def setattr(self, attrname, val):
if attrname == field_name and isinstance(val, int):
val = str(self.a + val) # <-- Crash. No attribute `a`
super_setattr(self, attrname, val)
wrapped_class.__setattr__ = setattr
return wrapped_class
return wrapped
@field_proxied("b")
class Foo(object):
def __init__(self):
self.a = 2
self.b = None
foo = Foo()
# <-- At this point, `foo` has no attribute `a`
foo.b = 4
assert foo.b == "6" # Became a string
问题很简单,改一行就可以了
def setattr(self, attrname, val):
if attrname == field_name and isinstance(val, int):
val = str(self.a + val)
super_setattr(self, attrname, val) # changed line
原因是,在你原来的方法中,你只会在attrname == field_name
时调用super_setattr
。所以 __init__
中的 self.a = 2
根本不起作用,因为 "a" != "b"
.