Python – 在类方法中传递类属性。

huangapple go评论62阅读模式
英文:

Python - Passing Class Attribute in Class Method

问题

如何使用类方法来更新变量类属性?

一个我认为能够捕捉到我所经历的情况的简单示例:

class Test():
    def __init__(self, a=None, b=None):
        self.a = a or ""
        self.b = b or ""

    def add_val(self, attrib, val, sep=";"):
        attrib = f'{attrib}{sep}{val}' if attrib else val

    def add_val_to_a(self, val, sep=";"):
        self.add_val(self.a, val, sep)

    def add_val_to_b(self, val, sep=";"):
        self.add_val(self.b, val, sep)

t = Test()
t.add_val_to_a("new_val")

预期结果应该是t.a = "new_val",但它仍然是''。

基本上,我想要根据一系列在类初始化时提供的条件来更新特定属性。但一旦条件被评估,"处理"在很大程度上都是相同的,我希望将它放入自己的方法中。

英文:

How can I use a class method to update a variable class attribute?

A trivial example that I believe captures what I'm experiencing:

class Test():
    def __init__(self, a=None, b=None):
        self.a = a or ""
        self.b = b or ""

    def add_val(self, attrib, val, sep=";"):
        attrib = f'{attrib}{sep}{val}' if attrib else val

    def add_val_to_a(self, val, sep=";"):
        self.add_val(self.a, val, sep)

    def add_val_to_b(self, val, sep=";"):
        self.add_val(self.b, val, sep)

t = Test()
t.add_val_to_a("new_val")

The intended result would be that t.a = "new_val", but it remains ''.

Essentially, I want to update specific attributes based on a series of conditions that are fed into the class upon initialization. But once the conditions are assessed, the "processing" is largely the same and I would like to stick it into its own method.

答案1

得分: 1

如果你有很多这些属性,并且希望它们都遵循相同的约定,你可以考虑实现__getattr__来在需要时自动生成属性及其对应的方法:

class Test:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def __getattr__(self, name: str):
        if not name.startswith("add_val_to_"):
            return ""
        var = name[11:]
        attrib = getattr(self, var)
        def add_val(val, sep=";"):
            setattr(
                self,
                var,
                f"{attrib}{sep}{val}" if attrib else val
            )
        return add_val

t = Test(a="old_val")
t.add_val_to_a("new_val")
print(t.a)  # old_val;new_val

然而,我通常建议如果你想要任意动态命名变量的行为,最好使用字典:

t = {"a": "old_val"}
def add_val(var, val, sep=";"):
    t[var] = f'{t[var]}{sep}{val}' if t.get(var) else val

add_val("a", "new_val")
print(t["a"])  # old_val;new_val

同样的效果,更简单的实现方式!

英文:

If you have a lot of these attributes, and you want them all to obey the same convention, you might consider implementing __getattr__ to automatically generate the attributes and their corresponding methods on demand:

class Test:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

    def __getattr__(self, name: str):
        if not name.startswith("add_val_to_"):
            return ""
        var = name[11:]
        attrib = getattr(self, var)
        def add_val(val, sep=";"):
            setattr(
                self,
                var,
                f"{attrib}{sep}{val}" if attrib else val
            )
        return add_val

t = Test(a="old_val")
t.add_val_to_a("new_val")
print(t.a)  # old_val;new_val

However, I'd usually suggest using a dict if you want the behavior of arbitrary dynamically named variables:

t = {"a": "old_val"}
def add_val(var, val, sep=";"):
    t[var] = f'{t[var]}{sep}{val}' if t.get(var) else val

add_val("a", "new_val")
print(t["a"])  # old_val;new_val

Same effect, much simpler implementation!

答案2

得分: 0

Let's go through a stack trace of your code.

# lets start with this line
t.add_val_to_a("new_val")

# now we call 'add_val_to_a'
# def add_val_to_a(self, val, sep=";"):
def add_val_to_a(self, "new_val", ";"):
    # self.add_val(self.a, val, sep)
    self.add_val('', "new_val", ";")

# now we call 'add_val'
# def add_val(self, attrib, val, sep=";"):
def add_val(self, '', "new_val", ";"):
    # attrib = f'{attrib}{sep}{val}' if attrib else val
    '' = f'{''}{;}{new_val}' if '' else new_val

As you can see on the last line, you're not actually setting the attribute to new_val, but instead you're setting an empty string variable to new_val. In order to actually change an unknown attribute, you need the __setattr__ function.

I took the liberty of modifying your code to conform to Python conventions:

class Test():
    def __init__(self, a='', b=''):
        self.a = a
        self.b = b

    def add_val(self, attr_name, val, sep=';'):
        attr = self.__getattribute__(attr_name)
        self.__setattr__(attr_name, f'{attr}{sep}{val}' if attr else val)

    def add_val_to_a(self, val, sep=';'):
        self.add_val('a', val, sep)

    def add_val_to_b(self, val, sep=';'):
        self.add_val('b', val, sep)

t = Test()
t.add_val_to_a('new_val')
print(t.a)

(Note: The code in your original message contains HTML entities like " and '. I have replaced them with their corresponding characters in the translated code.)

英文:

Let's go through a stack trace of your code.

# lets start with this line
t.add_val_to_a("new_val")

# now we call 'add_val_to_a'
# def add_val_to_a(self, val, sep=";"):
def add_val_to_a(self, "new_val", ";"):
    # self.add_val(self.a, val, sep)
    self.add_val('', "new_val", ";")

# now we call 'add_val'
# def add_val(self, attrib, val, sep=";"):
def add_val(self, '', "new_val", ";"):
    # attrib = f'{attrib}{sep}{val}' if attrib else val
    '' = f'{''}{;}{new_val}' if '' else new_val

As you can see on the last line, you're not actually setting the attribute to new_val, but instead you're setting an empty string variable to new_val. In order to actually change an unknown attribute, you need the __setattr__ function.

I took the liberty on modifying your code to conform to python conventions:

class Test():
    def __init__(self, a='', b=''):
        self.a = a
        self.b = b

    def add_val(self, attr_name, val, sep=';'):
        attr = self.__getattribute__(attr_name)
        self.__setattr__(attr_name, f'{attr}{sep}{val}' if attr else val)

    def add_val_to_a(self, val, sep=';'):
        self.add_val('a', val, sep)

    def add_val_to_b(self, val, sep=';'):
        self.add_val('b', val, sep)

t = Test()
t.add_val_to_a('new_val')
print(t.a)

</details>



# 答案3
**得分**: -1

`add_val`中的`attrib`是一个本地参数,它引用传递进来的对象。重新分配它不会对`self.a`产生任何影响。相反,返回生成的值并将其分配给要更改的变量:

```python
class Test():
    def __init__(self, a=None, b=None):
        self.a = a or ""
        self.b = b or ""

    def add_val(self, attrib, val, sep=";"):
        return f'{attrib}{sep}{val}' if attrib else val

    def add_val_to_a(self, val, sep=";"):
        self.a = self.add_val(self.a, val, sep)

    def add_val_to_b(self, val, sep=";"):
        self.b = self.add_val(self.b, val, sep)

t = Test()
t.add_val_to_a("new_val")
print(f'{t.a!r} {t.b!r}')
t.add_val_to_a("new_val")
print(f'{t.a!r} {t.b!r}')
t.add_val_to_b("new_val")
print(f'{t.a!r} {t.b!r}')
t.add_val_to_b("new_val")
print(f'{t.a!r} {t.b!r}')

输出:

'new_val' ''
'new_val;new_val' ''
'new_val;new_val' 'new_val'
'new_val;new_val' 'new_val;new_val'
英文:

attrib in add_val is a local parameter that references the passed in object. Reassigning it doesn't affect self.a at all. Instead, return the generated value and assign it to the variable to be changed:

class Test():
    def __init__(self, a=None, b=None):
        self.a = a or &quot;&quot;
        self.b = b or &quot;&quot;

    def add_val(self, attrib, val, sep=&quot;;&quot;):
        return f&#39;{attrib}{sep}{val}&#39; if attrib else val

    def add_val_to_a(self, val, sep=&quot;;&quot;):
        self.a = self.add_val(self.a, val, sep)

    def add_val_to_b(self, val, sep=&quot;;&quot;):
        self.b = self.add_val(self.b, val, sep)

t = Test()
t.add_val_to_a(&quot;new_val&quot;)
print(f&#39;{t.a!r} {t.b!r}&#39;)
t.add_val_to_a(&quot;new_val&quot;)
print(f&#39;{t.a!r} {t.b!r}&#39;)
t.add_val_to_b(&quot;new_val&quot;)
print(f&#39;{t.a!r} {t.b!r}&#39;)
t.add_val_to_b(&quot;new_val&quot;)
print(f&#39;{t.a!r} {t.b!r}&#39;)

Output:

&#39;new_val&#39; &#39;&#39;
&#39;new_val;new_val&#39; &#39;&#39;
&#39;new_val;new_val&#39; &#39;new_val&#39;
&#39;new_val;new_val&#39; &#39;new_val;new_val&#39;

huangapple
  • 本文由 发表于 2023年5月13日 10:25:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/76240835.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定