2014-10-29 104 views
5

在C++中,我們有static關鍵字,這在圈是這樣的:Python中的靜態變量?

for(int x=0; x<10; x++) 
    { 
     for(int y=0; y<10; y++) 
     { 
     static int number_of_times = 0; 
     number_of_times++; 
     } 
    } 

靜態使得這裏number_of_times初始化一次。我怎麼能在python 3.x中做同樣的事情?

編輯:由於大多數人弄糊塗了,我想指出的是,我給的代碼是靜態的使用只是例子在C++中。我真正的問題是,我想初始化只有一個時間變量函數,因爲我不希望它是全球性(等等!)或默認參數..

+0

聲明該變量的外部for循環。 – 2014-10-29 12:51:33

+5

這不是唯一聲明局部變量'static'的東西。請告訴我們你想用Python中的變量做什麼,以及你實際想要解決什麼問題([閱讀關於XY問題](http://meta.stackexchange.com/questions/66377/what-is-在-XY-問題))。 – 2014-10-29 12:54:19

+0

請注意,Python的範圍比C++少得多,因此對此類構造的需求較少。此代碼的Python版本中的'number_of_times'不會被限制在inner for循環中。 – chepner 2014-10-29 12:54:35

回答

8

假設你想要的是「在第一次函數調用時只初始化一次的變量」,Python語法中就沒有這種東西。但也有方法可以得到類似的結果:

1 - 使用一個全球性的。需要注意的是在Python中,「全球性」的真正意義的全球到模塊',而不是「全球的過程」:

_number_of_times = 0 

def yourfunc(x, y): 
    global _number_of_times 
    for i in range(x): 
     for j in range(y): 
      _number_of_times += 1 

2 - 在一個類中總結你的代碼,並使用一個類屬性(即:一個屬性這是所有實例共享的)。:

class Foo(object): 
    _number_of_times = 0 

    @classmethod 
    def yourfunc(cls, x, y): 
     for i in range(x): 
      for j in range(y): 
       cls._number_of_times += 1 

請注意,我用了一個classmethod因爲這個代碼片斷不會從一個實例

3需要什麼 - 總結你的代碼放在一個類,使用實例屬性和方法提供了捷徑:

class Foo(object): 
    def __init__(self): 
     self._number_of_times = 0 

    def yourfunc(self, x, y): 
     for i in range(x): 
      for j in range(y): 
       self._number_of_times += 1 

yourfunc = Foo().yourfunc 

4 - 寫一個可調用的類,並提供了捷徑:

class Foo(object): 
    def __init__(self): 
     self._number_of_times = 0 

    def __call__(self, x, y): 
     for i in range(x): 
      for j in range(y): 
       self._number_of_times += 1 


yourfunc = Foo() 

4之二 - 使用類屬性和元類

class Callable(type): 
    def __call__(self, *args, **kw): 
     return self._call(*args, **kw) 

class yourfunc(object): 
    __metaclass__ = Callable 

    _numer_of_times = 0 

    @classmethod 
    def _call(cls, x, y): 
     for i in range(x): 
      for j in range(y):     
       cls._number_of_time += 1 

5 - 做一個「創意」使用功能的默認參數在模塊的進口被實例化一次:

def yourfunc(x, y, _hack=[0]): 
    for i in range(x): 
     for j in range(y): 
      _hack[0] += 1 

仍然有一些其他可能的解決方案/黑客攻擊,但我認爲你現在可以看到大局。

編輯:給予操作的澄清,即「假設你有一個遞歸函數與默認參數,但如果有人實際上試圖給你的功能多一個參數可能是災難性的」,它看起來像OP真正想要什麼是這樣的:

# private recursive function using a default param the caller shouldn't set 
def _walk(tree, callback, level=0): 
    callback(tree, level) 
    for child in tree.children: 
     _walk(child, callback, level+1): 

# public wrapper without the default param 
def walk(tree, callback): 
    _walk(tree, callback) 

其中,順便說一句,證明我們真的然而,另一個問題XY ...

+0

我不明白爲什麼項目「4 bis」被標記爲這種方式。爲什麼不把它稱爲5並且將當前的5號碼稱爲6? – 2014-10-29 20:11:05

+0

@StevenRumbalski因爲它是一個編輯,我不想混淆已經存在的數字;) – 2014-10-29 20:27:51

2

您可以創建一個封閉與nonlocal,使他們可編輯(python 3 .x)。下面是一個計算列表長度的遞歸函數示例。

def recursive_len(l): 
    res = 0 
    def inner(l2): 
     nonlocal res 
     if l2: 
      res += 1 
      inner(l2[1:]) 
    inner(l) 
    return res 

或者,您可以爲函數本身分配一個屬性。從here使用的伎倆:

def fn(self): 
    self.number_of_times += 1 
fn.func_defaults = (fn,) 
fn.number_of_times = 0 

fn() 
fn() 
fn() 
print (fn.number_of_times) 
+0

在功能中不起作用。 – 2014-10-29 12:55:21

+1

「函數本身的屬性」非常脆弱,因爲它取決於名稱('fn')和函數對象之間的全局綁定以保持穩定。 – 2014-10-29 13:18:04

+0

爲什麼不直接在函數定義之後分配函數屬性? 'fn.number_of_times = 0'。 – 2014-10-29 13:36:37

1

您也可以使用全局關鍵字:

def main(args): 
    for i in xrange(10): 
     print i 
     global tmp 
     tmp = i 

但要小心......我大多數情況下比它解決它會增加更多的問題。

5

Python沒有靜態變量by design。對於你的例子,一般在循環塊等內部使用,你只需在外部範圍使用一個變量;如果這樣做過於長壽,那麼可能是時候考慮把這個功能分解成更小的功能。

對於繼續調用之間存在的功能,這只是一個重新實現對象和對象的方法的基本思想,所以你應該讓其中的一個,而不是一個變量。

0

的python中這樣做的另一種基於函數的方法是:

def f(arg, static_var=[0]): 
    static_var[0] += arg 

由於static_var對象在函數定義初始化,然後所有的呼叫重複使用,它會像一個靜態變量。請注意,您不能只使用int,因爲它們是不可變的。

>>> def f(arg, static_var=[0]): 
...   static_var[0] += arg 
...   print(static_var[0]) 
... 
>>> f(1) 
1 
>>> f(2) 
3 
>>> f(3) 
6 
+0

我實際上是想完全相反的:)我想刪除默認參數初始化static_var = [](例如)一次,然後改變它,但我喜歡在C++這可以用static關鍵字來完成,但顯然這功能沒有在Python中實現 – kuskmen 2014-10-29 15:58:20