代码之家  ›  专栏  ›  技术社区  ›  SuperCiocia

我能把这个写成包装纸吗?

  •  2
  • SuperCiocia  · 技术社区  · 6 年前

    我有以下代码:

    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 . 这是因为我提供的实际数组 库尔德 , [0,0], [1,0], [0,1] etc.是固定的,但可以在instance属性上扩展depedning dimension .

    我对python有点陌生,但凭直觉(也许是天真的)我认为这可以作为一个包装器来写…比如:

    @property
    def coord(self)
    

    @coord
    def Dcoord(self)
    

    这将使代码更加优雅。

    有人能帮我吗?

    6 回复  |  直到 6 年前
        1
  •  2
  •   chepner    6 年前

    定义自己的描述符 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
  •   blhsing    6 年前

    可以将属性名及其各自的常量值传递给 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)))
    
        3
  •  2
  •   blhsing    6 年前

    通过调用 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
  •   Dane White    6 年前

    你不能将值传递给属性获取器,而装饰器会很快变得笨重。如果至少使用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
  •  2
  •   martineau    6 年前

    通过这样做,您可以去掉很多样板代码:

    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]
    
        6
  •  0
  •   crazyGamer    6 年前

    就个人而言,我认为代码已经相当优雅了。 你不应该/不能 coord 属性,因为:

    • 您将无法向它传递参数,因为属性将是(计算的?)的“getter”。字段。 库尔德 作为一个函数,因此应该是一个函数。

    如果您真的只是想减少代码的大小,那么您可以尝试其他答案中的一种方法,尽管我认为这不是真正必要的。


    旁白:正如我从您的用例中了解到的,您希望允许用户能够调用 库尔德 有他们选择的自定义坐标吗?如果没有,可以考虑将其重命名为私有 _coord .