Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 调用对象时临时更改全局变量_Python_Python 3.x_Object - Fatal编程技术网

Python 调用对象时临时更改全局变量

Python 调用对象时临时更改全局变量,python,python-3.x,object,Python,Python 3.x,Object,我试图理解如何在调用对象时临时更改其属性,以及在不调用对象时保持原始值 让我用一些代码来描述这个问题: class DateCalc: DEFAULT= "1/1/2001" def __init__(self, day=DEFAULT): self.day= day def __call__(self, day=DEFAULT): self.day= day return self def getday(self): return self.day 如果用户在传递另一

我试图理解如何在调用对象时临时更改其属性,以及在不调用对象时保持原始值

让我用一些代码来描述这个问题:

class DateCalc:
 DEFAULT= "1/1/2001"
 def __init__(self, day=DEFAULT):
  self.day= day
 def __call__(self, day=DEFAULT):
  self.day= day
  return self
 def getday(self):
  return self.day
如果用户在传递另一个值时调用getday方法 i、 e 2002年2月2日,自我日设置为2002年2月2日。但是,我希望能够在方法调用后将self.day恢复为1/1/2001的原始值:

d_obj = DateCalc()
d_obj.getday() == "1/1/2001"
True
d_obj().getday() == "1/1/2001"
True
another_day_str = "2/2/2002"
d_obj(another_day_str).getday()
返回

"2/2/2002"
"2/2/2002"
但是当我运行以下命令时

d_obj.getday()
返回

"2/2/2002"
"2/2/2002"
我想知道什么是还原值的正确方法,而不需要在每个方法调用中包含代码。其次,在调用对象时也应该如此。例如:

d_obj().getday()
应该回来

"1/1/2001"
我以为调用魔术方法的装饰师会在这里工作,但我真的不确定从哪里开始


任何帮助都将不胜感激

您似乎想要一种类似于上下文管理器的行为:要在有限的时间内修改属性,请使用更新的属性,然后还原为原始属性。您可以通过让
\uuuu call\uuuu
返回一个上下文管理器来实现这一点,然后您可以在
块中使用上下文管理器,如下所示:

d_obj = DateCalc()
print(d_obj.getday())     # 1/1/2001
with d_obj('2/2/2002'):
    print(d_obj.getday()) # 2/2/2002
print(d_obj.getday())     # 1/1/2001
有几种方法可以创建这样的上下文管理器。最简单的方法是在
调用中使用嵌套方法,并用以下内容装饰它:

您也可以为此使用一个完全成熟的嵌套类,但我不建议您使用它,除非您有一些非常复杂的需求。我只是提供完整性:

def __call__(self, day=DEFAULT):
    class Context:
        def __init__(self, inst, new):
            self.inst = inst
            self.old = inst.day
            self.new = new
        def __enter__(self):
            self.inst.day = self.new
        def __exit__(self, *args):
            self.inst.day = self.old
    return Context(self, day)

也应该考虑编写<代码> GETEDA/COD>一个属性,特别是如果它是只读属性的时候。 另一种选择是让您的方法接受不同的值:

def getday(self, day=None):
    if day is None:
        day = self.day
    return day

这实际上是一个相当常见的习惯用法。

您似乎想要一种类似于上下文管理器的行为:要在有限的时间内修改属性,请使用更新的属性,然后还原为原始属性。您可以通过让
\uuuu call\uuuu
返回一个上下文管理器来实现这一点,然后您可以在
块中使用上下文管理器,如下所示:

d_obj = DateCalc()
print(d_obj.getday())     # 1/1/2001
with d_obj('2/2/2002'):
    print(d_obj.getday()) # 2/2/2002
print(d_obj.getday())     # 1/1/2001
有几种方法可以创建这样的上下文管理器。最简单的方法是在
调用中使用嵌套方法,并用以下内容装饰它:

您也可以为此使用一个完全成熟的嵌套类,但我不建议您使用它,除非您有一些非常复杂的需求。我只是提供完整性:

def __call__(self, day=DEFAULT):
    class Context:
        def __init__(self, inst, new):
            self.inst = inst
            self.old = inst.day
            self.new = new
        def __enter__(self):
            self.inst.day = self.new
        def __exit__(self, *args):
            self.inst.day = self.old
    return Context(self, day)

也应该考虑编写<代码> GETEDA/COD>一个属性,特别是如果它是只读属性的时候。 另一种选择是让您的方法接受不同的值:

def getday(self, day=None):
    if day is None:
        day = self.day
    return day

这实际上是一个相当常见的习惯用法。

由于您可能并不真的想修改对象的属性以获得定义不好的间隔,因此您需要返回或以其他方式创建另一个对象

最简单的情况是,您有两个单独的对象,并且根本没有调用方法:

d1_obj = DateCalc()
d2_obj = DateCalc('2/2/2002')
print(d1_obj.getday())  # 1/1/2001
print(d2_obj.getday())  # 2/2/2002
如果您知道在原始情况下要在何处使用
d_obj
vs
d_obj()
,那么您也清楚地知道在此版本中在何处使用
d1_obj
vs
d2_obj

如果
DateCalc
实际表示一个非常复杂的对象,并且该对象具有许多您不想更改的属性,则这可能不足以满足这种情况。在这种情况下,您可以让
\uuuuu call\uuuu
方法返回一个单独的对象,该对象智能地复制您想要的原始文件的部分

对于一个简单的例子,这可能只是

def __call__(self, day=DEFAULT):
    return type(self)(day)
如果对象变得足够复杂,则需要创建代理。代理是将大部分实现细节转发给另一个对象的对象。是一个具有高度定制实现的代理示例

在您的特定情况下,您有两个要求:

  • 代理必须存储所有重写的属性
  • 代理必须从原始对象获取所有未重写的属性
  • 代理必须将自身作为
    self
    参数传递给调用的任何(至少是非特殊)方法
  • 您可以随心所欲地处理这个问题(在这种情况下,请查看如何正确实现代理对象,如)。下面是一个相当简单的例子:

    # Assume that there are many fields like `day` that you want to modify
    class DateCalc:
        DEFAULT= "1/1/2001"
    
        def __init__(self, day=DEFAULT):
            self.day= day
    
        def getday(self):
            return self.day
    
        def __call__(self, **kwargs):
            class Proxy:
                def __init__(self, original, **kwargs):
                    self._self_ = original
                    self.__dict__.update(kwargs)
                def __getattribute__(self, name):
                    # Don't forward any overriden, dunder or quasi-private attributes
                    if name.startswith('_') or name in self.__dict__:
                        return object.__getattribute__(self, name)
                    # This part is simplified:
                    # it does not take into account __slots__
                    # or attributes shadowing methods
                    t = type(self._self_)
                    if name in t.__dict__:
                        try:
                            return t.__dict__[name].__get__(self, t)
                        except AttributeError:
                            pass
                    return getattr(self._self_, name)
            return Proxy(self, **kwargs)
    
    代理将完全按照您所希望的方式工作:它从原始对象转发您在
    \uuuuu调用中未重写的任何值。有趣的是,它将实例方法绑定到代理对象,而不是原始对象,这样
    getday
    就可以用一个
    self
    调用,该
    self
    中包含重写的值:

    d_obj = DateCalc()
    print(type(d_obj))    # __main__.DateCalc
    print(d_obj.getday()) # 1/1/2001
    
    d2_obj = d_obj(day='2/2/2002')
    print(type(d2_obj))     # __main__.DateCalc.__call__.<locals>.Proxy
    print(d2_obj.getday())  # 2/2/2002
    


    这里的问题是代理版本的
    day
    只是一个常规的可写属性,而不是只读属性。如果这对您来说是一个问题,那么在代理上适当地实现
    \uuuu setattr\uuuu
    将留给读者作为练习。

    因为您可能并不真的想修改对象的属性以获得定义不好的间隔,所以您需要返回或以其他方式创建一个不同的对象

    最简单的情况是,您有两个单独的对象,并且根本没有调用方法:

    d1_obj = DateCalc()
    d2_obj = DateCalc('2/2/2002')
    print(d1_obj.getday())  # 1/1/2001
    print(d2_obj.getday())  # 2/2/2002
    
    如果您知道在原始情况下要在何处使用
    d_obj
    vs
    d_obj()
    ,那么您也清楚地知道在此版本中在何处使用
    d1_obj
    vs
    d2_obj

    如果
    DateCalc
    实际表示一个非常复杂的对象,并且该对象具有许多您不想更改的属性,则这可能不足以满足这种情况。在这种情况下,您可以让
    \uuuuu call\uuuu
    方法返回一个单独的对象,该对象智能地复制您想要的原始文件的部分

    对于一个简单的例子,这可能只是

    def __call__(self, day=DEFAULT):
        return type(self)(day)
    
    如果对象变得足够复杂,则需要创建代理。代理是转发大多数实现的对象A