Python: 通过引用将类成员项传递给它的一个成员函数。

问题描述 投票:0回答:2

我在一个类中有一些函数,这些函数对类成员进行操作。这些函数除了操作的类成员外,几乎完全相同。为了避免重复输入函数,只改变被改变的类成员,我创建了一个函数,其中一个参数是要改变的类成员。

这里是一个非常简化的版本。

class Foo:
    a = 0
    b = 0

    def __set_member(self, member, value):
        member = value

    def set_a(self, value):
        self.__set_member(self.a, value)

f = Foo()

print(f.a)
f.set_a(2)
print(f.a)

但是这个输出:

0
0

在C++中,这可以用:

class Foo {

    void set_member(int& member, int value) {
        member = value;
    }

public:
    int a = 0;
    int b = 0;

    void set_a(int value) {
        set_member(this->a, value);
    }
};

很明显,我所举的例子不需要用到 "类成员"。set_member 函数,因为它非常简单。

在我的实际代码中,setter的样子是这样的。

def requestOpenDoor1(self):
    # Non blocking function: sets door1 to `Opening` and then after 2 seconds sets it to `Open`
    self.__door1 = DoorStates.Opening
    async def callback(): self.__door1 = DoorStates.Open
    self.__tasks.append(AsyncTimer(2, callback))

一种方法是把这个函数复制粘贴20多次,然后只修改被修改的类成员、过渡状态、时间和endState,但我宁愿减少代码的重复。

我也尝试过使用装饰器来解决这个问题。

class request_function_decorator(object):
    def __init__(self, tasks, stateToChange, transitionState, time, endState):
        self.__tasks = tasks
        self.__stateToChange = stateToChange
        self.__transitionState = transitionState
        self.__time = time
        self.__endState = endState
    def __call__(self, function):
        def wrapped_f(*args):
            self.__stateToChange = self.__transitionState
            async def callback(): self.__stateToChange = self.__endState
            self.__tasks.append(AsyncTimer(self.__time, callback))
        return wrapped_f

@request_function_decorator(__tasks, __door1, States.Opening, 2, States.Open)
def requestOpenDoor1(self):
    pass

但这也是行不通的。

如何将这个函数通用化,以减少代码的重复?

谢谢,我有一个类里面的一些函数。

python python-3.x pass-by-reference
2个回答
1
投票

你应该有 __setattr__ 的默认值。

class Foo:
    a = 0
    b = 0

f = Foo()
print(f.a)
# 0

f.a = 9
print(f.a)
# 9

f.__setattr__("a", 99)
print(f.a)
# 99

setattr(f, "a", 900)
print(f.a)
# 900

0
投票

你的第一个代码段的Python等价物就是这个。

class Foo:
    def __init__(self):
        # instances attributes must be defined on the instance, 
        # not on the class.
        self.a = 0
        self.b = 0

    def set_a(self, a):
        setattr(self, "a", a)

f = Foo()

print(f.a)
f.set_a(2)
print(f.a)

现在注意这里 set_a 是--从pythonic的角度来看--一个完整的WTF:首先它完全没有用处(a 是一个公共属性,你可以直接设置它),那么它的实现就使用了 setattr 无缘无故的(你可以直接把它当作 self.a = a.

FWIW,你在Python中很少会发现显式的setters getters。Python对计算属性有很强的支持,所以如果你打算公开暴露一个属性(这就是getterssetters的目标和效果),你就从一个普通的属性开始,如果并且当需要控制对它的访问时,你就把它变成一个计算属性,即。

class Foo:
    def __init__(self):
        # instances attributes must be defined on the instance, 
        # not on the class.
        self.a = 0
        self.b = 0

    @property
    def a(self):
        return self._a

    @a.setter 
    def a(self, a):
        if a == 42:
            raise HitchikerError("yes, but what is the question ?")  
        self._a = a

还要注意,实现属性(不属于类公共接口的属性)的规范命名惯例是一个单引号下划线。双引号下划线的东西(以及它所引发的命名人系统)只是为了防止在深度继承层次结构中意外的名称冲突,在实践中几乎从未使用过(因为几乎不需要)。

希望这能帮到你...


-1
投票

你可以通过将类变量变成可突变的列表对象来获得类似指针的效果。

显然,有人不喜欢我这里的例子。我在这里演示的东西在典型的代码中不应该是必需的;然而,来自CC++背景的人可能会有一些意义。它展示了一个类似的案例,在这个案例中,用指针来思考与通过索引引用一个列表并将其传递给方法和函数有相似之处。

>>> class Foo:
...     _a = [0]   # Class vars.
...     _b = [0]
...     
...     def __init__(self):
...         self._c = [0]  # Instance var.
... 
...     def _set_member(self, member, value): 
...         # Some lengthy algorithm you don't want to 
...         # implement separately for each data member...
...         member[0] = value
... 
...     @property
...     def a(self):
...         return self._a[0]
...         
...     @a.setter
...     def a(self, value):
...         self._set_member(self._a, value)
...         
>>> f = Foo()
>>> f.a
0
>>> f.a = 22
>>> f.a
22
>>> 

C语言的指针同样可以使用零索引来解除引用。int *a; ...a[0] = 1;.

有一次,当我使用Python C API实现本地库的接口时,我需要为几个需要多个指针作为参数的函数编写包装器。我希望保持Python函数的参数列表与C函数接近。所以我为这些参数使用了列表来模仿指针效应。

© www.soinside.com 2019 - 2024. All rights reserved.