我有以下代码:
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)
这会使代码更加优雅。
有人可以帮我吗?
答案 0 :(得分:2)
您可以将属性名称及其相应的常数值以元组序列的形式传递给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)))
方法,然后使用循环相应地设置属性:
{{1}}
答案 1 :(得分:2)
定义自己的描述符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))
现在,确定每种坐标类型的逻辑已嵌入到描述符本身中,而不是您的类中。
一些例子:
>>> Basis(1).dcoord
[1, 0]
>>> Basis(3).dcoord
[1, 0, 0]
>>> Basis(4).tcoord
[0, 1, 0, 0]
答案 2 :(得分:2)
通过这种方式,您可以摆脱很多样板代码:
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]
答案 3 :(得分:2)
您可以使用装饰器来包装这些方法,方法是为它们调用coord
方法并将其转换为属性,这样这些方法只需要返回相关的常量即可:
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)]
答案 4 :(得分:2)
您不能将值传递给属性获取器,装饰器将变得笨拙。如果您使用的是租约3.4,则可以使用functools.partialmethod减少行数。
但是,最好按原样保留代码,因为“显式比隐式更好”。
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)])
答案 5 :(得分:0)
就我个人而言,我认为代码已经很不错了。 您不应/不能将coord
设为财产,因为:
coord
表现为一种功能,因此应该是一个。如果您真的只是想减少代码的大小,则可以尝试其他答案中的一种方法,尽管我认为这并不是必须的。
此外:据您所知,您想允许用户使用自己选择的自定义坐标来呼叫coord
吗?如果没有,则可以考虑将其重命名为_coord
。