8

我正在尝试创建一个脚本来设置一个局部变量,从一个函数中引用它,并且可以将操纵值返回到主范围(或者它被称为什么;我是 Python 新手)

我已经简化了我的代码,以展示我想要完成的最基础的工作,我认为是将模块中的本地导入到功能块中。

我已经通过使用来实现这一点globals,但这不是最好的解决方案。. .

chambersinreactor = 0;
cardsdiscarded = 0;

def find_chamber_discard(): 
    """Find chambers and discard in row (reads each player slot)"""
    chambersinreactor = 0; # Resets the variable, not what I want
    cardsdiscarded = 0; # Resets the variable, not what I want
    chambersinreactor += 1
    cardsdiscarded += 1
    return # Don't know what to put here

find_chamber_discard()

print chambersinreactor # prints as 0, should be 1
print cardsdiscarded    # prints as 0, should be 1
4

3 回答 3

21

函数不必知道它们被调用的范围;函数的重点是制作一个可重用的代码块,可以从不同的地方多次调用。

您通过函数的输入变量将信息传递给函数。该函数通过返回信息将信息传回给它的调用者。

管理范围的变量是该范围内代码的工作,而不是它调用的任何函数。如果您需要将变量设置为由函数确定的值,那么您可以让函数返回这些值并使用它们来设置变量。如果函数计算的值取决于调用范围内的变量值,那么您需要将它们作为参数传递给函数。你调用的函数不应该知道你正在使用什么变量,也不应该弄乱它们。

把所有这些放在一起,你想要做的是这样的:

def find_chamber_discard(chambersinreactor, cardsdiscarded):
    chambersinreactor += 1
    cardsdiscarded += 1
    return (chambersinreactor, cardsdiscarded)

chambersinreactor = 0;
cardsdiscarded = 0;

chambersinreactor, cardsdiscarded = find_chamber_discard(chambersinreactor, cardsdiscarded)

print chambersinreactor
print cardsdiscarded

有一些方法可以通过全局变量或操纵可变数据结构来解决这个问题,但最终它们会使您的程序不那么灵活,并且更有可能包含难以发现的错误。这些技术有一席之地,但是您要与函数进行信息交流的第一种方法实际上应该是传递参数和接收返回值。

于 2012-05-11T03:44:52.597 回答
2

一种方法是使用可变值,例如字典或列表:

settings = dict(
    chambersinreactor = 0,
    cardsdiscarded = 0
)

def find_chamber_discard():
    settings['chambersinreactor'] += 1
    settings['cardsdiscarded'] += 1

find_chamber_discard()

print settings['chambersinreactor']
print settings['cardsdiscarded']

但是,如果您有一个正在更改某些状态的函数,那么最好将它们全部包装在类中,因为这就是它们的用途:

class CardCounter(object):
    def __init__(self):
        chambersinreactor = 0
        cardsdiscarded = 0

    def find_chamber_discard(self, hand):
        for card in hand:
            if card.is_chamber:
                self.chambersinreactor += 1
            if card.is_discarded:
                self.cardsdiscarded += 1

如果你正在做的是计数,也许你可以使用 Counter:

from collections import Counter

def test_for_chamberness(x): return x == 'C'
def test_for_discarded(x): return x == 'D'

def chamber_or_discard(card):
    if test_for_chamberness(card):
        return 'chambersinreactor'
    if test_for_discarded(card):
        return 'cardsdiscarded'

hand = ['C','C','D','X','D','E','C']

print Counter(
    x for x in (chamber_or_discard(card) for card in hand) if x is not None
)

就个人而言,我会选择类方法,甚至可能包装 Counter,因为它将所有相关功能保持在一起。

于 2012-05-11T05:45:04.497 回答
2
#!/usr/bin/env python
chambersinreactor = 0; cardsdiscarded = 0;

def find_chamber_discard():
    chambersinreactor = 0
    cardsdiscarded = 0
    chambersinreactor += 1 
    cardsdiscarded += 1 
    return(chambersinreactor, cardsdiscarded)

#Here the globals remain unchanged by the locals.
#In python, a scope is similar to a 'namespace'
find_chamber_discard()

print chambersinreactor #prints as 0
print cardsdiscarded 

#I've modified the function to return a pair (tuple) of numbers.
#Above I ignored them. Now I'm going to assign the variables in the 
#main name space to the result of the function call.
print("=====with assignment===")
(chambersinreactor, cardsdiscarded) = find_chamber_discard()

print chambersinreactor #  now prints as 1
print cardsdiscarded 

# Here is another way that doesn't depend on returning values.
#Pass a dictionary of all the main variables into your function
#and directly access them from within the function as needed

print("=======using locals===")
def find_chamber_discard2(_locals):
    _locals['chambersinreactor'] += 1
    _locals['cardsdiscarded'] += 1
    return

find_chamber_discard2(locals())

print chambersinreactor #incremented the value, which was already 1
print cardsdiscarded 
于 2012-05-11T03:53:02.420 回答