可以在 Python 的类中调用有状态函数吗?

Posted

技术标签:

【中文标题】可以在 Python 的类中调用有状态函数吗?【英文标题】:Possible to call stateful function in a class in Python? 【发布时间】:2020-09-17 08:28:02 【问题描述】:

是否可以在 Python 中直接设置某个值并通过任何方式(继承、元类、类装饰器)在类中获取它? B类不能被A中的set('a')污染。

import sys


class A:
    set('a')
    get()
    # -> 'a'

    print(sys.modules[__name__])
    # => <module '__main__'>


class B:
    get()
    # -> None

【问题讨论】:

setget 到底在做什么? 对于A 类,set('a')A 类(但不是它的实例)的'a' 保存到内存中。 get() 从内存中获取保存的'a'。它不必在getting 时从内存中删除'a'。如果set() 被调用两次,第一个值将被第二个值覆盖。在 B 中,get() 尝试获取为类 B 保存的任何值。但是,它没有任何价值。因为,set() 没有在 B 中调用。 这告诉我你想要他们做什么;我问他们实际上在做什么:显示定义。 实际上,setget 做什么是任意的。但是,假设他们所做的会影响 Python 中答案的实现方式,这是一个示例; ``` a = 无;默认设置(值):a = 值; def get(): 返回一个; ``` 但是,这个例子显然不适用于我的第一个例子。这能回答你的问题吗? set 正在创建一个局部变量;它不会更改全局变量 aA 的类属性的值。 【参考方案1】:

这两个独立的类不相互引用,所以只要你不将同一个对象传递给它们,那么它们都不会“污染”另一个。要设置一个值并获取一个对象的值,你可以使用这样的东西:

class A:
    def __init__(self):
        self.letter = None
    def set_value(self, letter):
        self.letter = letter
    def get_value(self):
        return self.letter if self.letter else '(none set)'

class B:
    def __init__(self):
        self.letter = None
    def set_value(self, letter):
        self.letter = letter
    def get_value(self):
        return self.letter if self.letter else '(none set)'

>>> a = A()
>>> aa = A()
>>> b = B()
>>> a.set_value('z')
>>> print(f'values in a, aa, and b are: a.get_value(), aa.get_value(), b.get_value()')
values in a, aa, and b are: z, (none set), (none set)

如您所见,设置a 对象的字母不会将其设置在b(不同的类)或aa 中,后者是同一个A 类的不同实例。希望对您有所帮助!

编码愉快!

【讨论】:

不幸的是,这与我要求的不同。我想要一个等价物而不创建 A 和 B 的实例。 不幸的是,我无法真正说出您的要求。您可以在一个类上获取和设置值,并且它不会被另一个类污染。 “设置一个特定的值并以任何方式将它放在一个类中”并不提供信息。设置一个值并再次取回它并不复杂,所以我认为你可能只是缺少一些关于你需要的细节的额外细节。随意添加更多的问题。 我的代码告诉我我想要什么......元编程和实例级编程是两个非常不同的方案。请查看您的代码是否适用于我的代码。还是谢谢【参考方案2】:

假设您知道自己在做什么,是的,可以在类主体中使用编程名称设置值,然后检索,并将这些值限制在该类主体中。

您所要做的就是使用locals() 调用来获取命名空间字典,并使用该字典来保存您的值:

class A:
    locals()["key"] = "a"
    print(locals()["key"] )

这将打印“a”, 显然,这个值不会是 B 类命名空间的一部分。

如果您只想存储值而不关联,那么 有一个名字,stackfull 项目提供了一个 pushpop 调用的行为就像 你在你的例子中提出 - 但是如果您尝试使用pop() 而不是以前的push 在同一范围内,您将收到一个错误,原因是 堆栈下溢:


In [4]: !pip install stackfull                                                                 
Collecting stackfull
...
Successfully installed stackfull-1.0.0


In [5]: from stackfull import push, pop                                                        

In [6]: class A: 
   ...:     push("a") 
   ...:     push("b") 
   ...:     print(pop()) 
   ...:     print(pop()) 
   ...:                                                                                        
b
a
In [7]: class B: 
   ...:     pop() 
   ...:   
...
StackUnderflowError:

(免责声明 - 我是 stackfull 包的作者。我从来不需要 除了已经存在的内容之外的任何内容,因此很长时间没有更新 - 并且使用 Python 3.8 中的“海象”运算符,它不再那么有用)

好的 - 所以我列出了这个,因为它类似于您问题中的代码,但您可能需要更主流的东西,例如在方法中编写代码,并设置实例属性。

【讨论】:

非常感谢。我从您的建议中提出了一些实现想法:) 在您建议的第一个示例中,locals()["key"] 的分配值在我的情况下将是您可能期望的函数。您是否通过更新本地人提出任何副作用?我要做的一件事是它可以覆盖类主体中的现有函数。

以上是关于可以在 Python 的类中调用有状态函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

从移交的类中调用对象

我可以/如何...在 PHP 中的类之外调用受保护的函数

python的类和对象中的super函数的问题

delphi中覆盖override父类的静态方法和虚函数有啥不同?

可以继续添加带有增加的类变量的调用函数吗?

我可以在所述类中调用我的函数中的类吗?