我可以把它写成包装器吗?
Can I write this as a wrapper?
我有以下代码:
import numpy as np
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
@property
def zerocoord(self):
return self.coord([0,0])
@property
def Dcoord(self):
return self.coord([1,0])
@property
def Tcoord(self):
return self.coord([0,1])
@property
def Xcoord(self):
return self.coord([1./np.sqrt(2), 1./np.sqrt(2)])
@property
def Ycoord(self):
return self.coord([-1./np.sqrt(2), 1./np.sqrt(2)])
其中所有属性基本上每个属性都在调用相同的方法coord
。这是因为我提供的实际数组 coord
、[0,0], [1,0], [0,1]
等是固定的,但可能会根据实例属性 dimension
.
进行扩展
我对 Python 有点陌生,但直觉上(也许天真地)我认为这可以写成包装器...所以类似于:
@property
def coord(self)
和
@coord
def Dcoord(self)
这会使代码更优雅。
有人可以帮我吗?
个人觉得代码已经很优雅了。 您不应该t/can将coord
设为属性,因为:
- 您将无法向其传递参数,因为 属性 意味着(计算的?)字段的 "getter"。
coord
表现为一个函数,因此应该是一个函数。
如果您真的只是想减少代码的大小,您可以尝试其他答案中的方法,但我认为这并不是真正必要的。
旁白:据我从您的用例中了解到,您希望允许用户使用他们选择的自定义坐标调用 coord
?如果不是,您可以考虑通过将其重命名为 _coord
.
来使其私有化
您可以将要传递给 coord
方法的 属性 名称及其各自的常量值放在一个元组序列中,然后使用循环相应地设置属性:
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
for name, value in ('zerocoord', [0, 0]), ('Dcoord', [1, 0]), ('Tcoord', [0, 1]), ('Xcoord', [1./np.sqrt(2), 1./np.sqrt(2)]), ('Ycoord', [-1./np.sqrt(2), 1./np.sqrt(2)]):
setattr(Basis, name, property(lambda self, value=value: self.coord(value)))
定义您自己的描述符 Coord
,而不是使用 property
。
from __future__ import division
import numpy as np
class Coord(object):
def __init__(self, p1, p2):
self.foo = [p1, p2]
def __get__(self, obj, type=None):
if obj.dimension > 2:
return self.foo + [0 for x in range(2, obj.dimension)]
else:
return self.foo
class Basis(object):
def __init__(self, d):
self.dimension = d
zerocoord = Coord(0, 0)
dcoord = Coord(1, 0)
tcoord = Coord(0, 1)
xcoord = Coord(1/np.sqrt(2), 1/np.sqrt(2))
ycoord = Coord(-1/np.sqrt(2), -1/np.sqrt(2))
现在,确定每种类型坐标形状的逻辑嵌入在描述符本身中,而不是您的 class。
一些例子:
>>> Basis(1).dcoord
[1, 0]
>>> Basis(3).dcoord
[1, 0, 0]
>>> Basis(4).tcoord
[0, 1, 0, 0]
您可以通过这种方式摆脱大量样板代码:
import numpy as np
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
return c if self.dimension <= 2 else (c + [0]*(self.dimension-2))
def _coord_prop(loc):
@property
def prop(self):
return self.coord(loc)
return prop
zerocoord = _coord_prop([0, 0])
Dcoord = _coord_prop([1, 0])
Tcoord = _coord_prop([0, 1])
Xcoord = _coord_prop([1./np.sqrt(2), 1./np.sqrt(2)])
Ycoord = _coord_prop([-1./np.sqrt(2), 1./np.sqrt(2)])
del _coord_prop # Only used inside class definition.
basis = Basis(2)
print(basis.zerocoord) # -> [0, 0]
print(basis.Dcoord) # -> [1, 0]
print(basis.Tcoord) # -> [0, 1]
print(basis.Xcoord) # -> [0.7071067811865475, 0.7071067811865475]
print(basis.Ycoord) # -> [-0.7071067811865475, 0.7071067811865475]
您可以使用装饰器来包装这些方法,方法是为它们调用 coord
方法并将它们转换为属性,这样这些方法只需要 return 相关常量即可:
def coord_property(func):
def wrapper(self):
return self.coord(func(self))
return property(wrapper)
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
@coord_property
def zerocoord(self):
return [0,0]
@coord_property
def Dcoord(self):
return [1,0]
@coord_property
def Tcoord(self):
return [0,1]
@coord_property
def Xcoord(self):
return [1./np.sqrt(2), 1./np.sqrt(2)]
@coord_property
def Ycoord(self):
return [-1./np.sqrt(2), 1./np.sqrt(2)]
您不能将值传递给 属性 getter,装饰器会很快变得笨拙。如果您至少使用 3.4,则可以使用 functools.partialmethod.
减少行数
但是,最好保持代码原样,因为 "Explicit is better than implicit"。
from functools import partialmethod
class BasisWrapped(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
zerocoord = partialmethod(coord, [0, 0])
d_coord = partialmethod(coord, [1, 0])
t_coord = partialmethod(coord, [0, 1])
x_coord = partialmethod(coord, [1./np.sqrt(2), 1./np.sqrt(2)])
y_coord = partialmethod(coord, [-1./np.sqrt(2), 1./np.sqrt(2)])
我有以下代码:
import numpy as np
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
@property
def zerocoord(self):
return self.coord([0,0])
@property
def Dcoord(self):
return self.coord([1,0])
@property
def Tcoord(self):
return self.coord([0,1])
@property
def Xcoord(self):
return self.coord([1./np.sqrt(2), 1./np.sqrt(2)])
@property
def Ycoord(self):
return self.coord([-1./np.sqrt(2), 1./np.sqrt(2)])
其中所有属性基本上每个属性都在调用相同的方法coord
。这是因为我提供的实际数组 coord
、[0,0], [1,0], [0,1]
等是固定的,但可能会根据实例属性 dimension
.
我对 Python 有点陌生,但直觉上(也许天真地)我认为这可以写成包装器...所以类似于:
@property
def coord(self)
和
@coord
def Dcoord(self)
这会使代码更优雅。
有人可以帮我吗?
个人觉得代码已经很优雅了。 您不应该t/can将coord
设为属性,因为:
- 您将无法向其传递参数,因为 属性 意味着(计算的?)字段的 "getter"。
coord
表现为一个函数,因此应该是一个函数。
如果您真的只是想减少代码的大小,您可以尝试其他答案中的方法,但我认为这并不是真正必要的。
旁白:据我从您的用例中了解到,您希望允许用户使用他们选择的自定义坐标调用 coord
?如果不是,您可以考虑通过将其重命名为 _coord
.
您可以将要传递给 coord
方法的 属性 名称及其各自的常量值放在一个元组序列中,然后使用循环相应地设置属性:
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
for name, value in ('zerocoord', [0, 0]), ('Dcoord', [1, 0]), ('Tcoord', [0, 1]), ('Xcoord', [1./np.sqrt(2), 1./np.sqrt(2)]), ('Ycoord', [-1./np.sqrt(2), 1./np.sqrt(2)]):
setattr(Basis, name, property(lambda self, value=value: self.coord(value)))
定义您自己的描述符 Coord
,而不是使用 property
。
from __future__ import division
import numpy as np
class Coord(object):
def __init__(self, p1, p2):
self.foo = [p1, p2]
def __get__(self, obj, type=None):
if obj.dimension > 2:
return self.foo + [0 for x in range(2, obj.dimension)]
else:
return self.foo
class Basis(object):
def __init__(self, d):
self.dimension = d
zerocoord = Coord(0, 0)
dcoord = Coord(1, 0)
tcoord = Coord(0, 1)
xcoord = Coord(1/np.sqrt(2), 1/np.sqrt(2))
ycoord = Coord(-1/np.sqrt(2), -1/np.sqrt(2))
现在,确定每种类型坐标形状的逻辑嵌入在描述符本身中,而不是您的 class。
一些例子:
>>> Basis(1).dcoord
[1, 0]
>>> Basis(3).dcoord
[1, 0, 0]
>>> Basis(4).tcoord
[0, 1, 0, 0]
您可以通过这种方式摆脱大量样板代码:
import numpy as np
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
return c if self.dimension <= 2 else (c + [0]*(self.dimension-2))
def _coord_prop(loc):
@property
def prop(self):
return self.coord(loc)
return prop
zerocoord = _coord_prop([0, 0])
Dcoord = _coord_prop([1, 0])
Tcoord = _coord_prop([0, 1])
Xcoord = _coord_prop([1./np.sqrt(2), 1./np.sqrt(2)])
Ycoord = _coord_prop([-1./np.sqrt(2), 1./np.sqrt(2)])
del _coord_prop # Only used inside class definition.
basis = Basis(2)
print(basis.zerocoord) # -> [0, 0]
print(basis.Dcoord) # -> [1, 0]
print(basis.Tcoord) # -> [0, 1]
print(basis.Xcoord) # -> [0.7071067811865475, 0.7071067811865475]
print(basis.Ycoord) # -> [-0.7071067811865475, 0.7071067811865475]
您可以使用装饰器来包装这些方法,方法是为它们调用 coord
方法并将它们转换为属性,这样这些方法只需要 return 相关常量即可:
def coord_property(func):
def wrapper(self):
return self.coord(func(self))
return property(wrapper)
class Basis(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
@coord_property
def zerocoord(self):
return [0,0]
@coord_property
def Dcoord(self):
return [1,0]
@coord_property
def Tcoord(self):
return [0,1]
@coord_property
def Xcoord(self):
return [1./np.sqrt(2), 1./np.sqrt(2)]
@coord_property
def Ycoord(self):
return [-1./np.sqrt(2), 1./np.sqrt(2)]
您不能将值传递给 属性 getter,装饰器会很快变得笨拙。如果您至少使用 3.4,则可以使用 functools.partialmethod.
减少行数但是,最好保持代码原样,因为 "Explicit is better than implicit"。
from functools import partialmethod
class BasisWrapped(object):
def __init__(self, dimension):
self.dimension = dimension
def coord(self, c):
if self.dimension <= 2:
return c
else:
return c + [0]*(self.dimension-2)
zerocoord = partialmethod(coord, [0, 0])
d_coord = partialmethod(coord, [1, 0])
t_coord = partialmethod(coord, [0, 1])
x_coord = partialmethod(coord, [1./np.sqrt(2), 1./np.sqrt(2)])
y_coord = partialmethod(coord, [-1./np.sqrt(2), 1./np.sqrt(2)])