4

私は次のようなことをしたいと思います:

class Foo(object):
    def __init__(self):
        self.member = 10
        pass

def factory(foo):
    foo = Foo()

aTestFoo = None
factory(aTestFoo)

print aTestFoo.member

ただし、次のようにクラッシュしAttributeError: 'NoneType' object has no attribute 'member'ます。オブジェクトaTestFooは関数の呼び出し内で変更されていませんfactory

それを実行するためのpythonicの方法は何ですか?避けるべきパターンですか?それが現在の間違いである場合、それはどのように呼ばれますか?

C ++では、関数プロトタイプで、ファクトリで作成されるポインタへの参照を追加していました...しかし、これはPythonで考えるべきことではないかもしれません。

C#には、参照自体を変更できるキーワードがありref、C++の方法に非常に近いものです。私はJavaではわかりません...そしてPythonでは疑問に思います。

4

4 に答える 4

12

Pythonには参照渡しがありません。ちなみに、Javaと共有する数少ないものの1つです。Pythonで引数を渡すことを値による呼び出しとして説明する人もいれば(そして値を参照として定義する場合、参照はC ++での意味ではないことを意味します)、私がかなり疑わしいと思う理由で参照によって渡すこととして説明する人もいます(彼らはそれを再定義します) Pythonが「参照」と呼ぶものに使用し、何十年にもわたって参照渡しとして知られているものとは何の関係もないものになってしまうために、他の人はそれほど広く使用されて乱用されていない用語を使用します(人気のある例は「 {pass、call} by {object、sharing} ")。オブジェクトによる呼び出しを参照してくださいeffbot.orgで、さまざまな用語の定義、歴史、および用語の引数のいくつかの欠陥について、参照渡しおよび値渡しについてのかなり広範な議論を行っています。

名前を付けずに、短編小説は次のようになります。

  • すべての変数、オブジェクト属性、コレクションアイテムなど、オブジェクトを参照します。
  • 割り当て、引数の受け渡しなどにより、同じオブジェクトを参照する別の変数、オブジェクト属性、コレクションアイテムなどが作成されますが、他の変数、オブジェクト属性、コレクションアイテムなどがそのオブジェクトを参照するかどうかはわかりません。
  • 任意の変数、オブジェクト属性、コレクションアイテムなどを使用してオブジェクトを変更でき、他の変数、オブジェクト属性、コレクションアイテムなどを使用して、その変更を監視できます。
  • 変数、オブジェクト属性、コレクションアイテムなどは、別の変数、オブジェクト属性、コレクションアイテムなどを参照しません。したがって、変更可能なオブジェクト/コレクションを「名前空間」。これは非常に醜いので、はるかに簡単な代替手段(戻り値、例外、または反復可能な解凍による複数の戻り値など)がある場合は使用しないでください。

これは、Cでポインターを使用するのと同じように考えることができますが、ポインターへのポインター(ただし、ポインターを含む構造体へのポインターの場合もあります)ではありません。次に、それらのポインターを値で渡します。しかし、この直喩を読みすぎないでください。PythonのデータモデルはCのデータモデルとは大きく異なります。

于 2012-10-09T10:21:57.240 に答える
10

Pythonであるため、ここで間違いを犯しています

"We call the argument passing technique _call by sharing_,
because the argument objects are shared between the
caller and the called routine.  This technique does not
correspond to most traditional argument passing techniques
(it is similar to argument passing in LISP).  In particular it
is not call by value because mutations of arguments per-
formed by the called routine will be visible to the caller.
And it is not call by reference because access is not given
to the variables of the caller, but merely to certain objects."

Pythonでは、仮引数リストの変数は実際の引数オブ​​ジェクトにバインドされます。オブジェクトは呼び出し元と呼び出し先の間で共有されます。「新鮮な場所」や余分な「店舗」はありません。

(もちろん、これがCLUの人々がこのメカニズムを「共有による呼び出し」と呼んだ理由です。)

ところで、Python関数は拡張環境でも実行されません。機能体は周囲の環境へのアクセスが非常に制限されています。

于 2012-10-09T10:25:42.997 に答える
3

PythonドキュメントのAssignmentStatementsセクションは興味深いかもしれません。

Pythonの=ステートメントは状況によって動作が異なりますが、提示する場合は、新しいオブジェクトを新しいローカル変数にバインドするだけです。

def factory(foo):
    # This makes a new instance of Foo,
    # and binds it to a local variable `foo`,
    foo = Foo()

# This binds `None` to a top-level variable `aTestFoo`
aTestFoo = None

# Call `factory` with first argument of `None`
factory(aTestFoo)

print aTestFoo.member

役立つというよりも混乱を招く可能性がありますが、disモジュールは関数のバイトコード表現を表示できます。これにより、Pythonが内部でどのように機能するかを明らかにできます。`factoryの分解は次のとおりです。

>>> dis.dis(factory)
  4           0 LOAD_GLOBAL              0 (Foo)
              3 CALL_FUNCTION            0
              6 STORE_FAST               0 (foo)
              9 LOAD_CONST               0 (None)
             12 RETURN_VALUE        

つまり、PythonはグローバルFooクラスを名前(0)でロードし、それを呼び出し(3、インスタンス化と呼び出しは非常に似ています)、結果をローカル変数に格納します(6、STORE_FASTを参照)。次に、デフォルトの戻り値(9)をロードし、それNoneを返します(12)

それを実行するためのpythonicの方法は何ですか?避けるべきパターンですか?それが現在の間違いである場合、それはどのように呼ばれますか?

Pythonではファクトリ関数が必要になることはめったにありません。それらが必要な場合は、(渡された変数に割り当てようとするのではなく)ファクトリから新しいインスタンスを返すだけです。

class Foo(object):
    def __init__(self):
        self.member = 10
        pass

def factory():
    return Foo()

aTestFoo = factory()

print aTestFoo.member
于 2012-10-09T10:36:28.073 に答える
1

ファクトリメソッドは何も返しません-デフォルトでは、戻り値はNone。です。に割り当てますが、再割り当てしないでください。実際のエラーの原因はここにありますaTestFooNone

これらの問題の修正:

class Foo(object):
    def __init__(self):
        self.member = 10
        pass

def factory(obj):
    return obj()

aTestFoo = factory(Foo)
print aTestFoo.member

このようなパターンはPythonではそれほど一般的ではありませんが(つまり、ファクトリメソッド)、これはあなたが求めていると思うことを実行するはずです。

于 2012-10-09T10:22:31.287 に答える