4

Python の引数受け渡し規則と C# の引数受け渡し規則の主な違いがあるとすれば、それは何ですか?

私は Python に非常に精通しており、C# を学び始めたばかりです。オブジェクトがいつ参照渡しされるか、C# と Python の場合と同じように値渡しされるか、または覚えておく必要があるいくつかの重要な違いがあるかどうかについてのルールセットを考えることができるかどうか疑問に思っていました。

4

5 に答える 5

7

C# passes parameters by value unless you specify that you want it differently. If the parameter type is a struct, its value is copied, otherwise the reference to the object is copied. The same goes for return values.

You can modify this behavior using the ref or out modifier, which must be specified both in the method declaration and in the method call. Both change the behavior for that parameter to pass-by-reference. That means you can no longer pass in more complex expressions. The difference between ref and out is that when passing a variable to a ref parameter, it must have been initialized already, while a variable passed to an out parameter doesn't have to be initialized. In the method, the out parameter is treated as uninitialized variable and must be assigned a value before returning.

于 2012-09-15T14:32:59.580 に答える
3

Pythonは常に参照値の受け渡しを使用します。例外はありません。変数の割り当てとは、参照値を割り当てることを意味します。例外なし。任意の変数は、参照値にバインドされた名前です。いつも。

参照は、使用時に自動的に逆参照されるターゲットオブジェクトのアドレスと考えることができます。このように、ターゲットオブジェクトを直接操作しているように見えます。しかし、その間には常に参照があり、ターゲットにジャンプするためのもう1つのステップがあります。

更新されました-参照により合格することを証明する必要な例を次に示します。

引数を渡す例

引数が値で渡された場合、外部lstを変更できませんでした。緑はターゲットオブジェクト(黒は内部に格納されている値、赤はオブジェクトタイプ)、黄色は内部に参照値を持つメモリであり、矢印で示されています。青い実線の矢印は、関数に渡された参照値です(青い破線の矢印パスを介して)。醜い濃い黄色は内部辞書です。(実際には、緑色の楕円として描くこともできます。色と形は、それが内部にあることを示しているだけです。)

更新-参照例を渡すことに関するswap(a, b)fgbのコメントと、を書くことができないことに関するdelnanのコメントに関連していswapます。

コンパイルされた言語では、変数は型の値をキャプチャできるメモリ空間です。Pythonでは、variableは、ターゲットオブジェクトへの参照値を保持する参照変数にバインドされた名前(文字列として内部的にキャプチャされたもの)です。変数の名前は内部ディクショナリのキーであり、そのディクショナリ項目の値の部分はターゲットへの参照値を格納します。

他の言語での目的はswap、渡された変数の内容を交換することです。つまり、メモリ空間の内容を交換することです。これはPythonでも実行できますが、変更できる変数に対してのみ実行できます。つまり、メモリ空間のコンテンツを変更できます。これは、変更可能なコンテナタイプにのみ当てはまります。その意味での単純な変数は、その名前を別の目的で再利用できる場合でも、常に一定です。

関数が新しいオブジェクトを作成する必要がある場合、それを外部に取得する唯一の方法は、コンテナータイプの引数を使用するか、Pythonreturnコマンドを使用することです。ただし、Pythonはreturn構文的には、複数の引数の外側を渡すことができたかのように見えます。実際には、外部に渡された複数の値はタプルを形成しますが、タプルは構文的にさらに外部のPython変数に割り当てることができます。

他の言語で認識される変数のシミュレーションに関連する更新。メモリ空間は、単一要素のリスト、つまりもう1つのレベルの間接参照によってシミュレートされます。その後、swap(a, b)他の言語と同じように書くことができます。唯一の奇妙なことは、シミュレートされた変数の値への参照としてリストの要素を使用する必要があることです。この方法で他の言語の変数をシミュレートする必要がある理由は、コンテナー(それらのサブセット)のみがPythonで変更できる唯一のオブジェクトであるためです。

>>> def swap(a, b):
...   x = a[0]
...   a[0] = b[0]
...   b[0] = x
...
>>> var1 = ['content1']
>>> var2 = ['content2']
>>> var1
['content1']
>>> var2
['content2']
>>> id(var1)
35956296L
>>> id(var2)
35957064L
>>> swap(var1, var2)
>>> var1
['content2']
>>> var2
['content1']
>>> id(var1)
35956296L
>>> id(var2)
35957064L

今では、古典言語の「通常の」変数の外観をシミュレートしてvar1いることに注意してください。var2内容はswap変更されますが、アドレスは同じままです。

変更可能なオブジェクトの場合(たとえばリストのようにswap(a, b))、他の言語とまったく同じように書くことができます。

>>> def swap(a, b):
...   x = a[:]
...   a[:] = b[:]
...   b[:] = x[:]
...
>>> lst1 = ['a1', 'b1', 'c1']
>>> lst2 = ['a2', 'b2', 'c2']
>>> lst1
['a1', 'b1', 'c1']
>>> lst2
['a2', 'b2', 'c2']
>>> id(lst1)
35957320L
>>> id(lst2)
35873160L
>>> swap(lst1, lst2)
>>> lst1
['a2', 'b2', 'c2']
>>> lst2
['a1', 'b1', 'c1']
>>> id(lst1)
35957320L
>>> id(lst2)
35873160L

リストの内容のコピーを表現するには、 likeの複数の代入a[:] = b[:]を使用する必要があることに注意してください。

于 2012-09-15T14:45:42.100 に答える
3

Pythonを「値渡し」または「参照渡し」言語と呼び、C、C#などと比較する場合の問題は、Pythonのデータ参照方法の概念が異なることです。Pythonは、従来の値別または参照別の二分法に簡単に適合しないため、混乱と「値による呼び出しです!」につながります。「いいえ、それは参照による呼び出しです、そして私はそれを証明することができます!」「いいえ、あなたはマルーンです、それは明らかに価値による呼びかけです!」上で目撃した無限のループ。

真実は、どちらでもないということです。Pythonは、共有による呼び出し(別名、オブジェクトによる呼び出し)を使用します。これは、値による戦略(たとえば、、、、などのスカラー値を処理する場合)のようintに見える場合もあれば、参照による戦略(、、、、、などの構造化された値を処理する場合)のように見える場合もあります。PythonistaのようなDavidGoodgerのコードは、これを「他の言語には変数があり、Pythonには名前がある」と美しく要約しています。ボーナスとして、彼は違いを説明する明確なグラフィックを提供します。floatstrlistdictsetobject

裏では、共有による呼び出しは、参照による呼び出しのように実装されます(Noctis Skytowerによって言及された変更floatが示すように)。しかし、参照による呼び出しと考えると、軌道に乗らないことになります。参照は実装ですが、公開されたセマンティクスではないため、迅速に。

対照的に、C#は値による呼び出しまたは参照による呼び出しのいずれかを使用しますがout、C、Pascalなどで見られるように、このオプションは純粋な参照による呼び出しを超えた微調整を表すと主張する人もいるかもしれません。

したがって、PythonとC#は、アーキテクチャレベルでは、いずれにせよ、実際には非常に異なります。実際には、値による値と参照による組み合わせにより、詳細やコーナーケースにトリッキーな小さな悪魔が住んでいるにもかかわらず、共有による呼び出しと非常によく似た動作をするプログラムを作成できます。

比較コンテキストでさまざまな言語のパラメーター受け渡し戦略を理解することに興味がある場合は、 式評価戦略に関するWikipediaのページを読む価値があります。網羅的ではありませんが(この特定の猫の皮を剥ぐ方法はたくさんあります!)、最も重要な猫の範囲に加えて、いくつかの興味深い珍しいバリエーションをうまくカバーしています。

于 2012-09-15T19:25:32.490 に答える
2

Python は常に値渡しです。

def is_python_pass_by_value(foo):
    foo[0] = 'More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.'
    foo = ['Python is not pass-by-reference.']

quux = ['Yes, of course, Python *is* pass-by-value!']

is_python_pass_by_value(quux)

print(quux[0])
# More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.

refC# は既定で値渡しですが、メソッド宣言サイトと呼び出しサイトの両方でキーワードが使用されている場合は、参照渡しもサポートします。

struct MutableCell
{
    public string value;
}

class Program
{
    static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
    {
        foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
        foo = new string[] { "C# is not pass-by-reference." };

        bar.value = "For value types, it is *not* call-by-sharing.";
        bar = new MutableCell { value = "And also not pass-by-reference." };

        baz = "It also supports pass-by-reference if explicitly requested.";

        qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
    }

    static void Main(string[] args)
    {
        var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };

        var corge = new MutableCell { value = "For value types it is pure pass-by-value." };

        var grault = "This string will vanish because of pass-by-reference.";

        var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };

        IsCSharpPassByValue(quux, corge, ref grault, ref garply);

        Console.WriteLine(quux[0]);
        // More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.

        Console.WriteLine(corge.value);
        // For value types it is pure pass-by-value.

        Console.WriteLine(grault);
        // It also supports pass-by-reference if explicitly requested.

        Console.WriteLine(garply.value);
        // Pass-by-reference is supported for value types as well.
    }
}

ご覧のとおり、refキーワードによる明示的な注釈がなければ、C# はPython とまったく同じように動作します。値型は、渡される値がオブジェクト自体である値渡しです。参照型は、渡される値がオブジェクトへのポインターである値渡しです (call-by-object-sharing とも呼ばれます)。

Python は変更可能な値の型をサポートしていないため (おそらくこれは良いことです)、値渡しと値渡しの違いを観察することは不可能であるため、すべてを pass-pointer- として扱うことができます。値によって、メンタルモデルを大幅に簡素化します。

C# はoutパラメーターもサポートしています。それらも参照渡しですが、呼び出し先がそれらから読み取ることはなく、書き込むだけであることが保証されているため、呼び出し元は事前にそれらを初期化する必要はありません。これらは、Python でタプルを使用する場合に、複数の戻り値をシミュレートするために使用されます。それらは、一方向の参照渡しのようなものです。

于 2012-09-15T14:24:30.190 に答える
0

それほど変わらない

def func(a,b):
    a[0]=5 #Python
    b=30

public int func( ref int a,out int b,int d)
{
  a++;b--;  //C#
}

x=[10]
y=20
func(20,30) #python 
print x,y   #Outputs x=[5],y=20 Note:I have used mutable objects.Not possible with int.

int x=10,y=20;
func(ref x,out y,18); //C# 
Console.Writeline("x={0} y={1}",x,y);//Outputs x=11,y=19
于 2012-09-15T14:27:48.893 に答える