不使用“全局”访问函数外部的函数变量[重复]
- 2025-02-13 08:35:00
- admin 原创
- 38
问题描述:
我正在尝试访问 Python 中函数外部的局部函数变量。
我可以使用全局变量来使这样的代码工作:
bye = ''
def hi():
global bye
bye = 5
sigh = 10
hi()
print(bye)
接下来,我尝试了此代码,希望无需使用即可访问bye
外部:hi()
`global bye`
def hi():
bye = 5
sigh = 10
return
hi()
x = hi()
print(x.bye)
这给出了AttributeError: 'NoneType' object has no attribute 'bye'
。
接下来我尝试:
def hi():
bye = 5
sigh = 10
return bye
hi()
x = hi()
print(x.bye)
这并没有改善事情;我明白AttributeError: 'int' object has no attribute 'bye'
。
有没有一种方法可以在不使用全局变量的情况下访问函数bye
外部的局部函数变量(hi()
),并且不打印出该sigh
变量?我该怎么做?
解决方案 1:
您可以按照以下步骤进行操作(当我测试它/它们时,它在 Python v2.7.17 和 v3.8.1 中都有效):
def hi():
# other code...
hi.bye = 42 # Create function attribute.
sigh = 10
hi()
print(hi.bye) # -> 42
函数是 Python 中的对象,可以赋予任意属性。
如果您经常要做这种事情,那么可以通过创建一个函数装饰器来实现更通用的功能,该函数装饰器会this
在每次调用被装饰的函数时添加一个参数。
这个附加参数将为函数提供一种引用自身的方法,而无需将其名称明确嵌入(硬编码)到定义的其余部分中,并且类似于类方法自动接收作为其第一个参数的实例参数,该参数通常被命名self
- 我选择了不同的东西以避免混淆,但就像self
参数一样,它可以被命名为任何你想要的。
以下是该方法的一个例子:
def add_this_arg(func):
def wrapped(*args, **kwargs):
return func(wrapped, *args, **kwargs)
return wrapped
@add_this_arg
def hi(this, that):
# other code...
this.bye = 2 * that # Create function attribute.
sigh = 10
hi(21)
print(hi.bye) # -> 42
笔记
这不适用于类方法。只需使用self
已传递给方法的实例参数(按惯例命名),而不是方法的名称。您可以通过 引用类级属性type(self)
。请参阅类中的函数属性。
解决方案 2:
问题是您print(x.bye)
在设置x
为字符串后调用的。运行时,x = hi()
它会运行 hi() 并将 x 的值设置为 5(bye 的值;它不会将 x 的值设置为对 bye 变量本身的引用)。例如:bye = 5; x = bye; bye = 4; print(x)
打印 5,而不是 4。
此外,您不必运行hi()
两次,只需运行x = hi()
,而不是hi(); x=hi()
(您的方式是运行 hi(),不对结果值 5 执行任何操作,然后重新运行相同的 hi() 并将 5 的值保存到 x 变量。
所以完整的代码应该是
def hi():
bye = 5
sigh = 10
return bye
x = hi()
print(x)
如果要返回多个变量,一种选择是使用列表或字典,具体取决于您的需要。例如:
def hi():
return { 'bye': 5, 'sigh': 10 }
x = hi()
print x['bye']
解决方案 3:
def hi():
bye = 5
return bye
print hi()
解决方案 4:
为了能够访问局部函数的变量,可以添加函数名称并在局部变量名称前添加一个点(然后,当然,使用此构造在函数主体内和函数外部调用变量)。此解决方案适用于 Python 3.7.4。
例如:
def func(): # define a function
# here y is a local variable, which I want to access; func.y
# defines a method for my example function which will allow me to
# access function's local variable y
func.y = 4
x = func.y + 8
return x
func() # now I'm calling the function
a = func.y # I put its local variable into my new variable
print(a) # and print my new variable
解决方案 5:
你可以做类似的事情:
def static_example():
if not hasattr(static_example, "static_var"):
static_example.static_var = 0
static_example.static_var += 1
return static_example.static_var
print static_example()
print static_example()
print static_example()
解决方案 6:
如果要避免global
,一种可行的方法是定义一个类。每个类实例都有自己的属性;还有一个类属性空间,实例可以在其中共享一个属性。
如果您是 Python 新手,面向对象编程可能很难入门,但现在可能是开始尝试它的好时机。
class Thing:
shared = "foo"
def __init__(self):
"""
This gets called when you create a new Thing()
"""
self.bar = "baz" # default value for new instances
def get_bar(self):
return self.bar
def set_bar(self, value):
self.bar = value
现在,让我们创建两个实例。
first = Thing()
second = Thing()
get_bar
在类似本例的简单示例中,和方法set_bar
并非必需。您还可以执行
second.bar = "ick"
print(second.bar)
# "ick"
print(first.bar)
# "baz"
(尽管对于更复杂的情况,您可能希望要求用户调用 setter 和 getter 方法;有办法强制执行此操作 - 例如参见使用 getter 和 setter 的 Pythonic 方式是什么?)
如果通过一个实例更改类属性,则在其他实例中它也不会被更改。
second.shared = "poo"
print(first.shared)
# "foo"
但是如果你在类本身中改变它,它将在所有未单独覆盖共享值的实例中被改变。
Thing.shared = "zoom"
print(first.shared)
# "zoom"
print(second.shared)
# "poo", still
回顾一下,你Thing
通过调用 来创建一个新实例Thing()
;这将__init__
在返回新实例之前运行该方法。在类内部,实例是每个(非静态、非类)方法的第一个参数,并且通常被调用(尽管就 Python 解释器而言,如果你愿意,self
你可以调用它)。shirley
类还有很多内容;主要的卖点可能是您可以创建从其父类继承但可以覆盖某些行为的子类(常见的例子通常涉及现实世界的概念,如动物或车辆,但类可以是任何您想要创建类型并封装其行为的东西,并且可能覆盖派生类型中的一些方法)。