web-dev-qa-db-ja.com

Python:関数でローカル変数を使用し、関数から変数を返す

ローカル変数を設定し、それを関数から参照し、操作した値をメインスコープ(またはそれが呼び出されたものに戻すことができる; 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
7
Zhall

関数は、関数の呼び出し元のスコープを知っている必要はありません。関数のポイントは、異なる場所から複数回呼び出すことができる再利用可能なコードのブロックを作成することです。

関数への情報の伝達は、入力変数を介して関数を渡します。関数は、情報を返すことにより、呼び出し元に情報を返します。

スコープの変数の管理は、そのスコープ内のコードの仕事ですnotそれが呼び出すすべての関数。変数を関数によって決定された値に設定する必要がある場合は、関数にそれらの値を返させ、それらを使用して変数を設定します。関数が計算する値が、呼び出しスコープ内にある変数の値に依存している場合は、それらを引数として関数に渡す必要があります。呼び出す関数は、使用している変数を知っている必要はありません。また、変数をいじる必要もありません。

これらすべてをまとめると、あなたがしたいことは次のようなものです:

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

グローバル変数または可変データ構造を操作してこれを回避する方法はありますが、最終的にはプログラムの柔軟性が低下し、特定が困難なエラーが含まれる可能性が高くなります。これらの手法には場所がありますが、関数との間で情報をやり取りするために最初に到達する方法は、実際には引数を渡し、戻り値を受け取ることです。

20
Ben
#!/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 
2
lee

1つのアプローチは、dictやリストなどの変更可能な値を使用することです。

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

あなたがやっていることを数えているなら、多分あなたはカウンターを使うことができます:

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をラップすること)に行きます。

2
Matthew Trevor