英文:
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 ""
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}')
Output:
'new_val' ''
'new_val;new_val' ''
'new_val;new_val' 'new_val'
'new_val;new_val' 'new_val;new_val'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论