Могу ли я написать это как обертку? - PullRequest
0 голосов
/ 19 октября 2018

У меня есть следующий код:

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)

, что сделало бы код более элегантным.

Может кто-нибудь помочь мне?

Ответы [ 6 ]

0 голосов
/ 19 октября 2018

Вы не можете передать значение получателю свойства, и декораторы будут неуклюже спешить.Если вы используете в аренду 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)])
0 голосов
/ 19 октября 2018

Вы можете использовать декоратор, который упаковывает эти методы, вызвав для них метод 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)]
0 голосов
/ 19 октября 2018

Вы можете избавиться от большого количества стандартного кода, выполнив следующие действия:

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]
0 голосов
/ 19 октября 2018

Определите свой собственный дескриптор с именем 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]
0 голосов
/ 19 октября 2018

Вы можете поместить имена свойств и соответствующие им значения констант для передачи методу 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)))
0 голосов
/ 19 октября 2018

Лично я думаю, что код уже довольно элегантный. Вы не должны / не можете сделать coord свойством, потому что:

  • Вы не сможете передать ему аргументы, так как свойство предназначено длябыть «добытчиком» для (рассчитанного?) поля.coord ведет себя как функция и, следовательно, должно быть единым целым.

Если вы действительно просто хотите уменьшить размер своего кода, вы можете попробовать подход из других ответов, хотя я думаю, что этона самом деле не является необходимым.


В сторону: Как я понимаю из вашего варианта использования, вы хотите, чтобы пользователи могли звонить coord с произвольной координатой по своему выбору?Если нет, вы можете сделать его закрытым, переименовав его в _coord.

...