如何区分 class 内部和 class 外部设置为 ___setattr__ 的 属性?
How to differentiate between a property being set with ___setattr__ from inside the class and outside the class?
在 __setattr__()
中有什么方法可以区分来自 class 或 child/inheriting class 内部的属性集和来自当前外部的属性集或 child class?
我想从 "outside" 更改设置属性的工作方式,在我制作模块的情况下,我希望用户在设置属性时与在 [= 内部设置属性时具有不同的逻辑27=].
例如:
当从 class 中调用时 i.x = 5
应该正常分配 5 并且 i
是它的一个实例,但是当从另一个 class 中调用时它应该减去 5 而不是设置为 5。
一个解决方案可能是始终在 class 中使用 self.__dict__
,而不调用 __setattr__
方法。
示例:
class myClass:
def __init__(self, value):
self.__dict__['a'] = value
def __setattr__(self, name, value):
print("called from outside")
if name == 'a':
self.__dict__[name] = value - 5
else:
self.__dict__[name] = value
f = myClass(10)
print(f.a)
# 10
f.a = 20
print(f.a)
# called from outside
# 15
有点低级,但你可以使用 inspect
模块:
import inspect
class A:
def __init__(self):
self.__x = 0
@property
def x(self):
return self.__x
@x.setter
def x(self, value):
f = inspect.currentframe()
if 'self' in f.f_back.f_locals and issubclass(type(f.f_back.f_locals['self']), A):
print('Called from class!')
self.__x = -value
else:
print('Called from outside!')
self.__x = value
def fn(self):
print('Calling A.x from inside:')
self.x = 10
class B(A):
def __init__(self):
super().__init__()
def fn2(self):
print('Calling B.x from inside:')
self.x = 15
a = A()
print("A.x after init:", a.x)
print('Calling A.x from outside')
a.x = 10
print("A.x called from the outside:", a.x)
a.fn()
print("A.x called from the inside:", a.x)
b = B()
print("B.x after init:", b.x)
print('Calling B.x from outside')
b.x = 20
print("B.x called from the outside:", b.x)
b.fn2()
print("B.x called from the inside:", b.x)
打印:
A.x after init: 0
Calling A.x from outside
Called from outside!
A.x called from the outside: 10
Calling A.x from inside:
Called from class!
A.x called from the inside: -10
B.x after init: 0
Calling B.x from outside
Called from outside!
B.x called from the outside: 20
Calling B.x from inside:
Called from class!
B.x called from the inside: -15
使用 属性。在 class 内部,您可以直接分配给底层属性。在外部,对 x
的赋值反而会递减它。
class Foo:
def __init__(self):
self._x = 0
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x -= value
在 __setattr__()
中有什么方法可以区分来自 class 或 child/inheriting class 内部的属性集和来自当前外部的属性集或 child class?
我想从 "outside" 更改设置属性的工作方式,在我制作模块的情况下,我希望用户在设置属性时与在 [= 内部设置属性时具有不同的逻辑27=].
例如:
当从 class 中调用时 i.x = 5
应该正常分配 5 并且 i
是它的一个实例,但是当从另一个 class 中调用时它应该减去 5 而不是设置为 5。
一个解决方案可能是始终在 class 中使用 self.__dict__
,而不调用 __setattr__
方法。
示例:
class myClass:
def __init__(self, value):
self.__dict__['a'] = value
def __setattr__(self, name, value):
print("called from outside")
if name == 'a':
self.__dict__[name] = value - 5
else:
self.__dict__[name] = value
f = myClass(10)
print(f.a)
# 10
f.a = 20
print(f.a)
# called from outside
# 15
有点低级,但你可以使用 inspect
模块:
import inspect
class A:
def __init__(self):
self.__x = 0
@property
def x(self):
return self.__x
@x.setter
def x(self, value):
f = inspect.currentframe()
if 'self' in f.f_back.f_locals and issubclass(type(f.f_back.f_locals['self']), A):
print('Called from class!')
self.__x = -value
else:
print('Called from outside!')
self.__x = value
def fn(self):
print('Calling A.x from inside:')
self.x = 10
class B(A):
def __init__(self):
super().__init__()
def fn2(self):
print('Calling B.x from inside:')
self.x = 15
a = A()
print("A.x after init:", a.x)
print('Calling A.x from outside')
a.x = 10
print("A.x called from the outside:", a.x)
a.fn()
print("A.x called from the inside:", a.x)
b = B()
print("B.x after init:", b.x)
print('Calling B.x from outside')
b.x = 20
print("B.x called from the outside:", b.x)
b.fn2()
print("B.x called from the inside:", b.x)
打印:
A.x after init: 0
Calling A.x from outside
Called from outside!
A.x called from the outside: 10
Calling A.x from inside:
Called from class!
A.x called from the inside: -10
B.x after init: 0
Calling B.x from outside
Called from outside!
B.x called from the outside: 20
Calling B.x from inside:
Called from class!
B.x called from the inside: -15
使用 属性。在 class 内部,您可以直接分配给底层属性。在外部,对 x
的赋值反而会递减它。
class Foo:
def __init__(self):
self._x = 0
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x -= value