Python 对象实例中看似不可变的dict

Python 对象实例中看似不可变的dict,python,object,dictionary,immutability,cartopy,Python,Object,Dictionary,Immutability,Cartopy,如果我运行以下cartopycode: import cartopy.crs as ccrs globe = ccrs.LambertCylindrical() print(globe.proj4_params) globe.proj4_params['a'] = 5 print(globe.proj4_params) 我得到: {'proj': 'cea', 'lon_0': 0.0, 'a': 57.29577951308232, 'ellps': 'WGS84'} {'proj': 'c

如果我运行以下
cartopy
code:

import cartopy.crs as ccrs
globe = ccrs.LambertCylindrical()
print(globe.proj4_params)
globe.proj4_params['a'] = 5
print(globe.proj4_params)
我得到:

{'proj': 'cea', 'lon_0': 0.0, 'a': 57.29577951308232, 'ellps': 'WGS84'}
{'proj': 'cea', 'lon_0': 0.0, 'a': 57.29577951308232, 'ellps': 'WGS84'}
提示
proj4_params
属性是不可变的

但它只是一个bog标准
dict

print(type(globe.proj4_params))

<class 'dict'>
结果:

*** AttributeError: attribute 'proj4_params' of 'cartopy._crs.CRS' objects is not writable

通过先将参数转换为字典,可以确保参数是字典

params = dict(globe.proj4_params)
那么如果你打印

print type(params)

<type 'dict'>
打印类型(参数)

请注意问题中的
而不是
。您正在使用的dict可能是一个不可变的自定义类,但使用相同的
dict
名称。

您可以先将参数转换为一个字典,以确保它是一个字典

params = dict(globe.proj4_params)
那么如果你打印

print type(params)

<type 'dict'>
打印类型(参数)

请注意问题中的
而不是
。您正在使用的dict可能是一个自定义类,它是不可变的,但使用相同的
dict
名称。

proj4_params对象最终在
Projection
的超类
CRS
中定义,该类由cartopy中的私有cython模块
\u CRS.pyx
提供。当定义cartopy CRS的proj4_参数时,它只是定义为类内的变量,而不是类变量(也就是说,它不是定义为
self.proj4_参数
)。这就是为什么不能修改proj4参数的值的原因之一

无论如何,我相信这是cartopy CRS的正确行为方式。每个CRS的
proj4_params
元素直接引用了cartopy在Python中提供的底层投影的规范定义。这些规范定义由proj.4组织维护(例如,),因此修改
proj4_参数
将意味着您的投影不再是Lambert圆柱投影


如果您特别需要一个几乎是Lambert圆柱形的cartopy CRS,您可以通过复制cartopy自己的
Lambert圆柱形
类中的代码来创建自己的CRS。只要您在自己的类中维护继承,就应该能够像使用cartopy的内置CRS一样使用它。注意:如果您确实为自己的类修改了
proj4_参数
,它可能无法工作,因为您指定的参数与proj.4本身中的任何内容都不匹配。在这种情况下,您可以考虑修改CRS的属性以进行所需的投影更改

proj4_params对象最终在
Projection
的超类
CRS
中定义,该超类由cartopy中的私有cython模块
\u CRS.pyx
提供。当定义cartopy CRS的proj4_参数时,它只是定义为类内的变量,而不是类变量(也就是说,它不是定义为
self.proj4_参数
)。这就是为什么不能修改proj4参数的值的原因之一

无论如何,我相信这是cartopy CRS的正确行为方式。每个CRS的
proj4_params
元素直接引用了cartopy在Python中提供的底层投影的规范定义。这些规范定义由proj.4组织维护(例如,),因此修改
proj4_参数
将意味着您的投影不再是Lambert圆柱投影


如果您特别需要一个几乎是Lambert圆柱形的cartopy CRS,您可以通过复制cartopy自己的
Lambert圆柱形
类中的代码来创建自己的CRS。只要您在自己的类中维护继承,就应该能够像使用cartopy的内置CRS一样使用它。注意:如果您确实为自己的类修改了
proj4_参数
,它可能无法工作,因为您指定的参数与proj.4本身中的任何内容都不匹配。在这种情况下,您可以考虑修改CRS的属性以进行所需的投影更改

不过,我需要就地修改原始参数,而不是创建其副本。但这确实暗示了问题的存在,我已经编辑了这个问题。根据对您问题的更新,这似乎是不可能的。为什么需要就地编辑这些值?如果不可能,我仍然想知道为什么不可能。我知道您可以在C类中设置写权限,但这不会导致
类型
报告其他对象类型,例如
?对于应用程序,我正在编写一个函数,它将
ccrs
对象作为输入,并在不存在时修改它们以插入一些合理的默认值。由于这样做似乎不可能,我可能不得不使用自己的包装器,因为有…@ResMar它报告的是
,而不是
,因此它可能是一个自定义类,默认情况下是不可变的。不过,我需要修改原始参数,而不是创建它的副本。但这确实暗示了问题的存在,我已经编辑了这个问题。根据对您问题的更新,这似乎是不可能的。为什么需要就地编辑这些值?如果不可能,我仍然想知道为什么不可能。我知道您可以在C类中设置写权限,但这不会导致
类型
报告其他对象类型,例如
?对于应用程序,我正在编写一个函数,它将
ccrs
对象作为输入,并在不存在时修改它们以插入一些合理的默认值。因为这样做似乎不可能,我可能不得不自己卷包装纸,因为有…@ResMar,它报告的是
而不是
,所以它可能是一个自定义类,默认情况下是不可变的。我怀疑
globe.proj4_params
是一个属性,它在每次访问dict时为您提供一个新的dict副本,正是为了防止您这样做