CodeQL 文档

__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

点击查看 CodeQL 代码库中的查询

描述符协议允许用户对属性访问进行编程。描述符协议是使类方法、静态方法、属性和 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。

  • ©GitHub, Inc.
  • 条款
  • 隐私