Tüm Python sürümlerinde hem 3. hem de 4. sözdizimi hataları olmalıdır . Ancak, Python 2.5 - 3.4 sürümlerini etkileyen ve daha sonra Python sorun izleyicisine gönderilen bir hata buldunuz . Hata nedeniyle, parantezsiz bir üreteç ifadesi, yalnızca *args
ve / veya eşlik ediyorsa, bir işlevin argümanı olarak kabul edildi **kwargs
. Python 2.6+ hem 3. hem de 4. durumlara izin verirken, Python 2.5 yalnızca 3. duruma izin verir - ancak ikisi de belgelenen dilbilgisine aykırıdır :
call ::= primary "(" [argument_list [","]
| expression genexpr_for] ")"
yani belgeler der bir işlev çağrısı içerir primary
, yanında parantez içinde: (a çağrılabilir olarak değerlendirildiğini ifade), ya da bir bağımsız değişken listesi ya da sadece bir parantezsiz jeneratör ifade; ve bağımsız değişken listesi içinde, tüm üreteç ifadeleri parantez içinde olmalıdır.
Bu hata (bilinmemesine rağmen) Python 3.5 ön sürümlerinde düzeltildi. Python 3.5'te, işlevin tek bağımsız değişkeni bu olmadığı sürece, bir üretici ifadesinin etrafında parantezler her zaman 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 belgelenmiştir Python 3.5 'daki Yenilikler Yeni , bu hatayı tespit DeTeReR sayesinde.
Hatanın analizi
Python 2.6'da , şunlardan sonra anahtar kelime argümanlarının kullanılmasına izin*args
veren bir değişiklik yapıldı :
Bir işlev çağrısına * args argümanından sonra anahtar kelime argümanları sağlamak da yasal hale geldi.
>>> def f(*args, **kw):
... print args, kw
...
>>> f(1,2,3, *(4,5,6), keyword=13)
(1, 2, 3, 4, 5, 6) {'keyword': 13}
Önceden bu bir sözdizimi hatası olurdu. (Katkıda bulunan Amaury Forgeot d'Arc; sayı 3473.)
Bununla birlikte, Python 2.6 dilbilgisi , anahtar kelime argümanları, konumsal argümanlar veya çıplak üreteç ifadeleri arasında herhangi bir ayrım yapmaz - hepsi argument
ayrıştırıcı için türdendir.
Python kurallarına göre, işlevin yegane argümanı değilse bir üretici ifadesi parantez içine alınmalıdır. Bu şu şekilde doğrulanır Python/ast.c
:
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;
}
Bununla birlikte, bu işlev hiç dikkate almaz *args
- özellikle sadece sıradan konumsal argümanları ve anahtar kelime argümanlarını arar.
Aynı işlevde, anahtar kelime arg'den sonra anahtar kelime olmayan arg için oluşturulan bir hata mesajı vardır :
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 argümanlar için de geçerlidir değil olarak parantezsiz jeneratör ifadeleri kanıtladığı else if
açıklamada :
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, parantezsiz bir üretici ifadesinin kayarak geçmesine izin verildi.
Artık Python 3.5'te *args
bir işlev çağrısının herhangi bir yerinde kullanılabilir , bu nedenle Dilbilgisi buna uyacak şekilde değiştirildi:
arglist: argument (',' argument)* [',']
ve
argument: ( test [comp_for] |
test '=' test |
'**' test |
'*' test )
ve for
döngü değiştirildi için
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 hatayı düzeltir.
Ancak kasıtsız değişiklik, geçerli görünen yapıların
func(i for i in [42], *args)
ve
func(i for i in [42], **kwargs)
parantezsiz bir jeneratörün önüne geçtiği *args
veya **kwargs
şimdi çalışmayı durdurduğu.
Bu hatayı bulmak için çeşitli Python sürümlerini denedim. 2.5'te şunları elde edersiniz SyntaxError
:
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'in bazı ön sürümlerinden önce düzeltildi:
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
Bununla birlikte, parantezli oluşturucu ifadesi Python 3.5'te çalışır, ancak Python 3.4'te çalışmaz:
f(*[1], (2 for x in [2]))
Ve bu ipucu. Python 3.5'te *splatting
genelleştirilmiştir; bir işlev çağrısında herhangi bir yerde kullanabilirsiniz:
>>> print(*range(5), 42)
0 1 2 3 4 42
Gerçek böcek (jeneratör ile çalışma Yani *star
parantez olmadan) oldu aslında Python 3.5 giderilmiştir ve hata Python 3.4 ve 3.5 arasında değiştiğini şey bu bulunamadı