在 python 类中,有没有很酷的方法来表达“if x is None: x = self.x”?

Is there any cool way to express `if x is None: x = self.x` in python class?

提问人:Jongbin Won 提问时间:11/6/2023 最后编辑:wjandreaJongbin Won 更新时间:11/6/2023 访问量:156

问:

我只是在研究python OOP,真的很困惑什么时候使用,什么时候不使用。self

特别是当我想制作一个默认获取对象实例输入的方法,并且还想让它作为可以获取自定义参数输入的普通方法工作时, 我为该方法的所有参数键入有点麻烦。if x is None: x = self.x

示例如下。

from dataclasses import dataclass

@dataclass
class PlusCalculator():
    x: int = 1
    y: int = 2
    result: int = None
    
    def plus(self, x=None, y=None):
        if x is None: x = self.x    ## the bothersome part
        if y is None: y = self.y
        
        result = x + y
        self.result = result        ## also confusing...is it good way?
        
        return result
    
pc = PlusCalculator()
print(pc.plus())
print(pc.plus(4,5))

有没有好方法可以将实例变量用作函数参数的默认值?

哎呀 默认值 实例变量

评论

0赞 ShadowRanger 11/6/2023
@ScaryWombat:这将忽略实例属性值,而支持固定的默认值。
0赞 wjandrea 11/6/2023
self.result = result ## also confusing...is it good way?- 是的,这很令人困惑。你为什么要这样做?
2赞 Brian61354270 11/6/2023
有趣的事实:有一个用于后期绑定函数参数默认值的开放 PEP (PEP 671),如果接受它,您将可以编写类似def plus(self, x=>self.x, y=>self.y)
0赞 wjandrea 11/6/2023
你正在使用的东西在这个规模上是完全可以的。在实际代码中,您编写的是一个采用大量参数的方法,还是多个采用相同参数的方法?还是别的什么?另外,您是否要混合默认值和参数,例如说,?有关情况的更多细节可以帮助我们找到更好的解决方案。print(pc.plus(4))

答:

1赞 Ian Price 11/6/2023 #1

条件表达式是可读的、快速的、直观的

x = self.x if x is None else x

再:

有没有好方法可以将实例变量用作函数参数的默认值?

关于 - 的设置,除非您以后需要将其作为实例变量访问,否则应避免这种情况。因此,您可以将其简化为:self.result

@dataclass
class PlusCalculator():
    ...

    def plus(self, x=None, y=None):
        x = self.x if x is None else x
        y = self.y if y is None else y
        return x + y

评论

0赞 Jongbin Won 11/6/2023
哦,那个表情比原来的要酷得多。多谢!顺便说一句,您能解释更多关于“将其作为实例道具访问”的信息吗???再次感谢,伊恩。
0赞 Ian Price 11/6/2023
当然 - 实例变量是 设置的任何变量;它们与类实例本身的实例一起存在。在这种情况下,这将是计算器实例。如果要将结果保存到变量中,则无需存储最后一个结果,除非要通过其他方法/手段访问它self.<variable> = valueplus()self.result = ...
1赞 blhsing 11/6/2023 #2

一种更简洁的方法是创建一个方法装饰器,以便在调用包装方法时,将应用具有默认值的参数,该参数的属性值与使用对象的默认值声明的参数相同,该参数表示要替换的默认值。我建议此对象是专用于此目的的新对象(在以下示例中命名),而不是实际上可以用作修饰方法的预期参数值:selfDEFAULTNoneNone

from inspect import signature

def default_self(method):
    def wrapper(self, *args, **kwargs):
        bound = sig.bind(self, *args, **kwargs)
        bound.apply_defaults()
        for name in names:
            if bound.arguments[name] is DEFAULT:
                bound.arguments[name] = getattr(self, name)
        return method(*bound.args, **bound.kwargs)

    sig = signature(method)
    names = [name for name, param in sig.parameters.items() if param.default is DEFAULT]
    return wrapper

DEFAULT = object()

因此:

@dataclass
class PlusCalculator:
    x: int = 1
    y: int = 2
    result: int = None

    @default_self
    def plus(self, x=DEFAULT, y=DEFAULT):
        self.result = x + y # an intermediate variable is unnecessary
        return self.result

pc = PlusCalculator()
print(pc.plus())
print(pc.plus(4, 5))
print(pc.plus(y=3))
print(pc.plus(x=2, y=3))

输出:

3
9
4
5

演示:https://ideone.com/joPRKD