SORU
11 EYLÜL 2015, Cuma


Değişken fonksiyon jeneratörü olarak

Kimseye bir işlev için yalnızca konumsal bağımsız değişken olarak bir jeneratör geçen özel kurallar var gibi görünüyor neden açıklayabilir mi?

Eğer var ise:

>>> def f(*args):
>>>    print "Success!"
>>>    print args
  1. Bu beklendiği gibi çalışır.

    >>> f(1, *[2])
    Success!
    (1, 2)
    
  2. Bu beklendiği gibi çalışmaz.

    >>> f(*[2], 1)
      File "<stdin>", line 1
    SyntaxError: only named arguments may follow *expression
    
  3. Bu beklendiği gibi çalışır

    >>> f(1 for x in [1], *[2])
    Success! 
    (generator object <genexpr> at 0x7effe06bdcd0>, 2)
    
  4. Bu çalışır, ama neden anlamıyorum. Bunu 2 şekilde başarısız) olmamalı

    >>> f(*[2], 1 for x in [1])                                               
    Success!
    (generator object <genexpr> at 0x7effe06bdcd0>, 2)
    

CEVAP
11 EYLÜL 2015, Cuma


Hem 3. ve 4.gerekirbütün Python sürümlerinde sözdizimi hataları olabilir.Ancak Python sürümleri etkileyen bir hata buldum sonradan posted to the Python issue tracker olan 2.5 - 3.4. Bu hata nedeniyle, unparenthesized jeneratör ifadesi *args ve/veya **kwargs sadece eşlik etti Eğer bir işlev için bağımsız değişken olarak kabul edilmiştir. Python 2.6 iken, her iki durumda izin verilen 3. ve 4., Python 2.5 tek durum 3 izin verdi. - yine de documented grammar karşı olmuştur

call    ::=     primary "(" [argument_list [","]
                            | expression genexpr_for] ")"

yani belgelere bir işlev çağrısı primary oluşur (bir çağrı veren ifade) diyor, parantez içinde izlediyabir bağımsız değişken listesiyaunparenthesized üreteç ifadesi sadece bir; ve argüman listesi içinde, tüm jeneratör ifadeler parantez içinde olmalıdır.


Bu hata, bilinen hiç bir şeye sahip değilmiş gibi görünse de), Python 3.5 prereleases sabit olmuştu. Python ile 3.5 parantez içinde her zaman işlevi tek bağımsız değişken olduğu sürece jeneratör bir ifade mi gereklidir:

Python 3.5.0a4  (default:a3f2b171b765, May 19 2015, 16:14:41) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(1 for i in [42], *a)
  File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument

Bu şimdi What's New in Python 3.5, teşekkürler, bu hatayı tespit DeTeReR belgelenmiştir.


Hata analizi

Bir değişiklik 58**: 2.6 Python için yapılmış

Ayrıca yasal *bir besten sonra anahtar kelime argümanlar sunmak oldu bir işlev çağrısı için bağımsız değişken.

>>> def f(*args, **kw):
...     print args, kw
...
>>> f(1,2,3, *(4,5,6), keyword=13)
(1, 2, 3, 4, 5, 6) {'keyword': 13}

Daha önce bu sözdizimi bir hata olurdu. (Amaury katkıda Forgeot d'Arc; sorun 3473.)


Ancak, 2.6 grammar Python anahtar kelime argümanlar, konumsal bağımsız değişkenler, ya da çıplak jeneratör ifadeler arasında herhangi bir ayrım yapmaz - türü çözümleyici 32**.

Python kuralları gereğince, jeneratör bir ifade işlevi için tek argüman ise programlama dilinde * sembolü olmalı. Bu Python/ast.c doğrulanır:

for (i = 0; i < NCH(n); i  ) {
    node *ch = CHILD(n, i);
    if (TYPE(ch) == argument) {
        if (NCH(ch) == 1)
            nargs  ;
        else if (TYPE(CHILD(ch, 1)) == gen_for)
            ngens  ;
        else
            nkeywords  ;
    }
}
if (ngens > 1 || (ngens && (nargs || nkeywords))) {
    ast_error(n, "Generator expression must be parenthesized "
              "if not sole argument");
    return NULL;
}

Ancak bu işlevdeğil*args hiç dikkate - özellikle sadece sıradan konumsal bağımsız değişkenleri ve anahtar kelime argümanlar arar.

Aynı işlevi daha aşağı, bir hata iletisi non-keyword arg after keyword arg oluşturulur

if (TYPE(ch) == argument) {
    expr_ty e;
    if (NCH(ch) == 1) {
        if (nkeywords) {
            ast_error(CHILD(ch, 0),
                      "non-keyword arg after keyword arg");
            return NULL;
        }
        ...

Ama bu yine değişkenler için geçerlidirdeğilevidenced by the else if statement jeneratör ifadeler unparenthesized:

else if (TYPE(CHILD(ch, 1)) == gen_for) {
    e = ast_for_genexp(c, ch);
    if (!e)
        return NULL;
    asdl_seq_SET(args, nargs  , e);
}

Böylece unparenthesized jeneratör bir ifade pass kayma izin verildi.


Şimdi Python 3.5 *args herhangi bir işlev çağrısı, bu yüzden kullanabilirsiniz Grammar bunun için barındıracak şekilde değiştirildi:

arglist: argument (',' argument)*  [',']

ve

argument: ( test [comp_for] |
            test '=' test |
            '**' test |
            '*' test )

ve for loop was changed

for (i = 0; i < NCH(n); i  ) {
    node *ch = CHILD(n, i);
    if (TYPE(ch) == argument) {
        if (NCH(ch) == 1)
            nargs  ;
        else if (TYPE(CHILD(ch, 1)) == comp_for)
            ngens  ;
        else if (TYPE(CHILD(ch, 0)) == STAR)
            nargs  ;
        else
            /* TYPE(CHILD(ch, 0)) == DOUBLESTAR or keyword argument */
            nkeywords  ;
    }
}

Böylece hata düzeltme.

Ancak yanlışlıkla değişiklik geçerli görünümlü yapılar olduğunu

func(i for i in [42], *args)

ve

func(i for i in [42], **kwargs)

unparenthesized jeneratör öncelikli olduğu *args **kwargs şimdi çalışmayı durdurdu.


Bu hata bulmak için, farklı Python sürümleri denedim. 2.5 SyntaxError olsun istiyorum:

Python 2.5.5 (r255:77872, Nov 28 2010, 16:43:48) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
  File "<stdin>", line 1
    f(*[1], 2 for x in [2])

Ve bu Python 3.5 bazı yayın öncesi önce sabit oldu:

Python 3.5.0a4  (default:a3f2b171b765, May 19 2015, 16:14:41) 
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> f(*[1], 2 for x in [2])
  File "<stdin>", line 1
SyntaxError: Generator expression must be parenthesized if not sole argument

Ancak, programlama dilinde * sembolü jeneratör ifadesi, Python 3.5, ama Python 3.4 değil çalışmaz çalışır:

f(*[1], (2 for x in [2]))

Ve bu ipucu. Python 3.5 *splatting genel; her yerde bir işlev çağrısı kullanabilirsiniz:

>>> print(*range(5), 42)
0 1 2 3 4 42

Gerçek hata (jeneratör *star ile çalışmak parantez olmadan)olduPython 3.4 ve 3.5 arasında ne değişti gerçekten Python hata bulunamadı 3.5 ve sabit

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Anthony Cumia

    Anthony Cumi

    5 EYLÜL 2006
  • foreignimage

    foreignimage

    13 HAZİRAN 2006
  • Wronchi Animation

    Wronchi Anim

    9 Mayıs 2011