-
Notifications
You must be signed in to change notification settings - Fork 185
Description
Mutable datatypes initialized with unsafe defaults
Some of the attrs-derived classes in floris.simulation may be initialized with unsafe defaults for mutable data types (mutable vs immutable types in Python). In Python, list, set, and dict types are all mutable, and variables referring to mutable types act like pointers to the same memory. For mutable-type attributes in attrs-derived classes with defaults of empty instances of the mutable type, any instance of the class will refer to the same memory for these particular attributes.
See #750 (comment) for the initial report.
Example
from attrs import define, field
@define
class A:
x: list = field(default=[])
y: list = field(factory=list)
a1 = A()
a2 = A()
print(a1, a2)
a1.x.append(4)
a1.y.append(5)
print(a1, a2)The code above yields the following output:
A(x=[], y=[]) A(x=[], y=[])
A(x=[4], y=[5]) A(x=[4], y=[])
The first print-statement shows that the instances of class A are initialized with empty lists for both x and y attributes. In the second print-statement, appending a value to both attributes for the a1 instance is shown to also affect the x attribute of the a2 instance. The y attribute is not affected because it is declared with factory=list so a new instance of list is created for new instances of A.
This is also true of NumPy arrays, as shown below. NumPy arrays don't have an append method, but they are also mutable and their values can be changed directly leading to this same side effect.
from attrs import define, field
import numpy as np
@define
class A:
x: np.array = field(default=np.array([1,2,3]))
a1 = A()
a2 = A()
print(a1, a2)
a1.x[0] = 9
print(a1, a2)A(x=array([1, 2, 3])) A(x=array([1, 2, 3]))
A(x=array([9, 2, 3])) A(x=array([9, 2, 3]))
Impacts on FLORIS
The attrs library is used only in floris.simulation, so this issue is isolated to that package. While many class definitions have this issue, the use of append is generally discouraged for performance considerations. However, there are many instances where the values in NumPy arrays are modified directly including all of the solvers.
The ultimate impact is unclear, but I'll update this section as this issue is understood more.
Affected classes
Here's a first-pass list at affected classes.
- Nearly all attributes in Farm
- Nearly all attributes in FlowField
- Empirical Gauss velocity model defaults