在 __get__
或 __set__
方法中修改描述符。¶
ID: py/mutable-descriptor
Kind: problem
Security severity:
Severity: error
Precision: very-high
Tags:
- reliability
- correctness
Query suites:
- python-security-and-quality.qls
描述符协议允许用户对属性访问进行编程。描述符协议是使类方法、静态方法、属性和 super()
成为可能的因素。
描述符对象是类属性,它们控制实例属性的行为。因此,单个描述符对于类的所有实例都是通用的,并且在访问实例属性时不应被修改。
建议¶
不要修改描述符对象,而是创建一个包含必要状态的新对象。
示例¶
在这个示例中,描述符类 MutatingDescriptor
在一个属性中存储对 obj
的引用。
#This is prone to strange side effects and race conditions.
class MutatingDescriptor(object):
def __init__(self, func):
self.my_func = func
def __get__(self, obj, obj_type):
#Modified state is visible to all instances of C that might call "show".
self.my_obj = obj
return self
def __call__(self, *args):
return self.my_func(self.my_obj, *args)
def show(obj):
print (obj)
class C(object):
def __init__(self, value):
self.value = value
def __str__(self):
return ("C: " + str(self.value))
show = MutatingDescriptor(show)
c1 = C(1)
c1.show()
c2 = C(2)
c2.show()
c1_show = c1.show
c2.show
c1_show()
#Outputs:
#C: 1
#C: 2
#C: 2
在以下示例中,描述符类 NonMutatingDescriptor
每次调用 __get__
时都会返回一个新对象。
import types
#Immutable version, which is safe to share.
class NonMutatingDescriptor(object):
def __init__(self, func):
self.my_func = func
def __get__(self, obj, obj_type):
#Return a new object to each access.
return types.MethodType(self.my_func, obj)
def show(obj):
print (obj)
class C(object):
def __init__(self, value):
self.value = value
def __str__(self):
return ("C: " + str(self.value))
show = NonMutatingDescriptor(show)
c1 = C(1)
c1.show()
c2 = C(2)
c2.show()
c1_show = c1.show
c2.show
c1_show()
#Outputs:
#C: 1
#C: 2
#C: 1
参考资料¶
Python 语言参考:实现描述符。
Mark Lutz. 学习 Python, 第 30.6 节:方法是对象:绑定或未绑定。O’Reilly 2013 年。
一个现实世界的例子:NumPy Issue 5247。