Yeni dil özellikleri kullanan bir programda Python sürümünü nasıl kontrol edebilirim?


239

Python'un en azından belirli bir sürümünü gerektiren bir Python betiğim varsa, betiği başlatmak için Python'un önceki bir sürümü kullanıldığında incelikle başarısız olmanın doğru yolu nedir?

Hata mesajı verecek ve çıkacak kadar erkenden kontrolü nasıl alabilirim?

Örneğin, ternery operatörünü (2.5'te yeni) ve "with" bloklarını (2.6'da yeni) kullanan bir programım var. Komut dosyasının dediği ilk şey olan basit bir tercüman sürümü denetleyicisi rutini yazdım ... ancak o kadar da uzak değil. Bunun yerine, rutinlerim bile çağrılmadan komut dosyası python derlemesi sırasında başarısız oluyor. Bu nedenle, komut dosyasının kullanıcısı, çok basit bir sinax hata geri bildirimi görür - ki bu sadece bir Python'un yanlış sürümünü çalıştırma durumunun bir uzman olduğunu gerektirir.

Python sürümünü nasıl kontrol edeceğimi biliyorum. Sorun, bazı sözdiziminin Python'un eski sürümlerinde yasadışı olmasıdır. Bu programı düşünün:

import sys
if sys.version_info < (2, 4):
    raise "must use python 2.5 or greater"
else:
    # syntax error in 2.4, ok in 2.5
    x = 1 if True else 2
    print x

2.4 altında çalıştırıldığında, bu sonucu istiyorum

$ ~/bin/python2.4 tern.py 
must use python 2.5 or greater

ve bu sonuç değil:

$ ~/bin/python2.4 tern.py 
  File "tern.py", line 5
    x = 1 if True else 2
           ^
SyntaxError: invalid syntax

(Bir iş arkadaşınız için kanallık.)


3
"python sürümünü kontrol edin. Sorun python'un eski sürümlerinde bazı sözdiziminin yasadışı olması." Bunun nasıl bir sorun olduğunu anlamıyorum. Sürümü kontrol edebiliyorsanız, sözdizimi hatasını önleyebilirsiniz. Sürüm kontrolü sözdizimi için nasıl geçerli değildir? Sorunuzu açıklığa kavuşturabilir misiniz?
S.Lott

4
@ S.Lott Hayır yanlış değilsiniz, sadece zorluk kodu da okunmayacağı (ayrıştırılamayacağı) ve yürütülmeyeceği bir yere dahil etmektir - bu, cevapların gösterdiği gibi hemen görülmez.
Brendan

7
S.Lott, derlemediğiniz için testinizi python'un eski sürümünde gerçekleştiremezsiniz. Bunun yerine, genel bir sözdizimi hatası alırsınız. Örnek kodu 2.4 yorumlayıcıyla deneyin, sürüm testine giremeyeceğinizi göreceksiniz.
Mark Harrison

7
@ S.Lott Peki bu önemsiz olarak düşündüğünüze bağlı - kişisel olarak Python'un farklı sürümleri için ayrı dosyalar oluşturmayı veya fazladan süreçleri önemsiz olarak oluşturmayı düşünmezdim. Bu sorunun değerli olduğunu söyleyebilirim, özellikle Python'un düzgün ve sık sık şaşırtıcı hilelerle dolu olduğunu düşündüğünüzde - Google'dan buraya düzgün bir cevap olup olmadığını öğrenmek isteyen geldim
Brendan

7
Bence bu tartışmanın sonuna geldik. Nasıl yapılacağını bilmediğim bir şey hakkında bir soru sordum ve bana nasıl yapılacağını söyleyen bir cevap aldım. Hiçbir şey önermiyorum, orip'in benim için harika çalışan cevabını kabul ettim (aslında kanallık yaptığım iş arkadaşı). Viva Le Stack Taşması!
Mark Harrison

Yanıtlar:


111

Şunları kullanarak test edebilirsiniz eval:

try:
  eval("1 if True else 2")
except SyntaxError:
  # doesn't have ternary

Ayrıca, with bir Python 2.5, sadece eklemek kullanılabilir from __future__ import with_statement.

DÜZENLEME: yeterince erken kontrol elde etmek için, .pyiçe aktarmadan önce farklı dosyalara bölebilir ve ana dosyadaki uyumluluğu kontrol edebilirsiniz (örneğin __init__.pybir pakette):

# __init__.py

# Check compatibility
try:
  eval("1 if True else 2")
except SyntaxError:
  raise ImportError("requires ternary support")

# import from another module
from impl import *

10
bu harika bir cevap. adreslemenin gerekli olduğu sorusundaki ana sorun, bir programın python sürümünün yürütülmeye başlaması için sözdizimsel olarak doğru olması gerektiğidir, bu nedenle yeni sözdiziminin kullanılması bir programın yorumlayıcının eski sürümlerinden başlamasını engeller. eval etrafında çalışır
Autoplectic

7
Paket setuptools tarafından kuruluyorsa, kaynak dosyaları bayt-derleme başarısız olur. Ayrıca, bir çalışma zamanı hata mesajı üretmek için tüm eğriler biraz anlamsız görünüyor - neden sadece gereksinimleri belgelemek ve bunu bırakmıyor?
John Machin

2
Basit bir ifade yerine bir ifadeyi kontrol etmeye çalışıyorsanız execbunun yerine kullanmanız gerektiğini unutmayın eval. Bu hem py2k hem de py3k stderr için yazdıracak bir işlev yazmaya çalışırken ortaya çıktı.
Xiong Chiamiov

2
Ben bu çözümün daha temiz bir sürümü "kontroller" ayrı bir modül koymak ve (ithalat importdenemek / hariç istasyonu sarın) olacağını düşünüyorum . Bunun dışında başka şeyler de kontrol etmeniz gerekebileceğini unutmayın SyntaxError(örn. Yerleşik işlevler veya standart kütüphaneye eklemeler)
Steven

103

Programınızın etrafında aşağıdakileri yapan bir paketleyici bulundurun.

import sys

req_version = (2,5)
cur_version = sys.version_info

if cur_version >= req_version:
   import myApp
   myApp.run()
else:
   print "Your Python interpreter is too old. Please consider upgrading."

sys.version()2.0 öncesi Python tercümanları kullanan insanlarla karşılaşmayı planlıyorsanız da kullanmayı düşünebilirsiniz , ancak daha sonra düzenli ifadeler yapmanız gerekir.

Ve bunu yapmanın daha zarif yolları olabilir.


7
FYI, "cur_version> = req_version" koşullu olarak çalışmalıdır.
orip

4
sys.version_infobir işlev değildir.
nh2

3
Kodu başarılı bir şekilde koşullu içine koymak, gereksiz bir girinti ve mantığın eklenmesi olduğundan oldukça kötü bir uygulamadır. Sadece şunu yapın: if sys.version_info [: 2] <req_version: print "old"; sys.exit () - ve normal şekilde devam edin.
timss

1
Tim Peters, "Python'un Zen'i" nde şöyle diyor: "Daire iç içe olmaktan daha iyidir." (Bunu
python'a

1
@ChristopherShroba Teşekkür ederiz import this. Hoş bir saptırma.
Samuel Harmer

32

Deneyin

ithalat platformu
platform.python_version ()

Size "2.3.1" gibi bir dize vermelidir. Bu tam olarak istediğiniz gibi değilse "platform" yerleşik aracılığıyla zengin bir veri kümesi vardır. Ne istersen orada bir yerde olmalı.


4
-1: Güncellenmiş soruda açıklandığı gibi bu işe yaramıyor. Python'un daha yeni bir sürümünden herhangi bir sözdizimi kullanırsanız, dosyanız derlenmez ve derlenmezse sürümü çalıştıramaz ve kontrol edemez!
Scott Griffiths

1
@ScottGriffiths Run print(platform.python_version())yerine platform.python_version()!
Suriyaa

@ScottGriffiths Ayrıca cevabımı da inceleyin: stackoverflow.com/a/40633458/5157221 .
Suriyaa

22

Muhtemelen bu sürüm karşılaştırması yapmanın en iyi yolu kullanmaktır sys.hexversion. Bu önemlidir çünkü sürüm gruplarını karşılaştırmak tüm python sürümlerinde istenen sonucu vermeyecektir.

import sys
if sys.hexversion < 0x02060000:
    print "yep!"
else:
    print "oops!"

Bunun en zarif olduğunu düşünüyorum, ancak muhtemelen diğer geliştiriciler tarafından anlaşılması en kolay şey değil.
Nick Bolton

5
Hangi durumlarda sürüm gruplarını karşılaştırmak istediğiniz sonucu vermeyeceğinizi açıklayabilir misiniz?
SpoonMeiser

sürüm gruplarında alfasayısal değerler de bulunabilir.
sorin

8
-1: Güncellenmiş soruda açıklandığı gibi bu işe yaramıyor. Python'un daha yeni bir sürümünden herhangi bir sözdizimi kullanırsanız, dosyanız derlenmez ve derlenmezse sürümü çalıştıramaz ve kontrol edemez!
Scott Griffiths

Bu hangi sürümde / platformda başarısız oluyor?
sorin

15
import sys    
# prints whether python is version 3 or not
python_version = sys.version_info.major
if python_version == 3:
    print("is python 3")
else:
    print("not python 3")

7
Aşağıdaki Python 2.6 ve, unutmayın sys.version_infoolduğunu değil adlandırılmış tanımlama grubu. sys.version_info[0]Büyük sürüm numarası ve sys.version_info[1]küçük sürüm için kullanmanız gerekir .
coredumperror

9

En Nykakin dan Yanıt Ask Ubuntu :

Python sürümünü platformstandart kitaplık modülünü kullanarak kodun kendisinden de kontrol edebilirsiniz .

İki işlev vardır:

  • platform.python_version() (dize döndürür).
  • platform.python_version_tuple() (tuple döndürür).

Python kodu

Örneğin bir dosya oluşturun: version.py)

Sürümü kontrol etmek için kolay yöntem:

import platform

print(platform.python_version())
print(platform.python_version_tuple())

evalYöntemi de kullanabilirsiniz :

try:
  eval("1 if True else 2")
except SyntaxError:
  raise ImportError("requires ternary support")

Python dosyasını bir komut satırında çalıştırın:

$ python version.py 
2.7.11
('2', '7', '11')

Windows 10'da bir WAMP Sunucusu üzerinden CGI ile Python çıkışı:

Ekran görüntüsü 2016-11-16 14.39.01 Suriyaa Kudo tarafından


Yardımcı kaynaklar


7

Setler geriye dönük olarak uyumlu kalmak için Python 2.4'teki temel dilin bir parçası oldu. O zamanlar bunu yaptım, ki bu senin için de işe yarayacak:

if sys.version_info < (2, 4):
    from sets import Set as set

3
sürümü yerine özelliği kontrol etmek daha iyi, değil mi? try: set except NameError: from sets import Set as set
OriP

@orip: Neden? Bir özelliğin hangi sürümde sunulduğunu biliyorsanız, buradaki ayarlar gibi, yukarıdaki kodu kullanın. Bunda yanlış bir şey yok.
André

7

Soru olmasına rağmen: Nasıl bir hata mesajı vermesi için yeterince erken kontrolünü alabilirim ve çıkış ?

Yanıtladığım soru şu: Uygulamayı başlatmadan önce bir hata mesajı verecek kadar erken nasıl kontrol alabilirim ?

Diğer mesajlardan çok daha farklı cevap verebilirim. Şimdiye kadar cevaplar Python içinden sorunuzu çözmeye çalışıyor.

Python'u başlatmadan önce sürüm kontrolü yapıyorum. Yolunuzun Linux veya unix olduğunu görüyorum. Ancak size yalnızca bir Windows betiği sunabilirim. Linux betik sözdizimine uyarlamak çok zor olmazdı.

İşte 2.7 sürümü ile DOS komut dosyası:

@ECHO OFF
REM see http://ss64.com/nt/for_f.html
FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul
IF NOT ErrorLevel 1 GOTO Python27
ECHO must use python2.7 or greater
GOTO EOF
:Python27
python.exe tern.py
GOTO EOF
:EOF

Bu, uygulamanızın hiçbir bölümünü çalıştırmaz ve bu nedenle bir Python İstisnası oluşturmaz. Herhangi bir geçici dosya oluşturmaz veya herhangi bir işletim sistemi ortam değişkeni eklemez. Ayrıca, farklı sürüm sözdizimi kuralları nedeniyle uygulamanızı bir istisna ile bitirmez. Bu, daha az olası üç güvenlik erişim noktasıdır.

FOR /FHat anahtarıdır.

FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul

Birden fazla python sürümü için url'ye göz atın: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

Ve hack versiyonum:

[MS betiği; Python modülünün Python sürüm kontrolü ön raporu] http://pastebin.com/aAuJ91FQ


Bu aşağı oylar için lütfen nedenlerini açıklamaktan korkmayın.
DevPlayer

Tam aradım. Teşekkürler! %% H nedir?
Clocker

@Clocker python.exe -V bir "Python 2.7" dizesi döndürür. Konsol otomatik olarak oluşturulan os var %% H (G'den sonraki harf) içinde "Python" dizesini %% G ve "2.7" dizesine koyar. Yankı %% H | DOS komutuna "2.7" borular "2.7" bulmak "2.7" %% H bulunursa hata düzeyini 1 olarak ayarlar "2.7" bulun. DOS find komutunu kullanarak 1 ile sonuçlanan bu hata seviyesi, DOS toplu iş etiketine geçmemize izin verecektir: Python27
DevPlayer

3
import sys
sys.version

böyle cevap alacak

'2.7.6 (varsayılan, 26 Eki 2016, 20:30:19) \ n [GCC 4.8.4]'

burada 2.7.6 sürümü


2

Yukarıda belirtildiği gibi, sözdizimi hataları çalışma zamanında değil derleme zamanında ortaya çıkar. Python "yorumlanmış bir dil" olsa da, Python kodu aslında doğrudan yorumlanmaz; daha sonra yorumlanacak bayt koduna derlenir. Bir modül içe aktarıldığında (.pyc veya .pyd dosyası biçiminde zaten derlenmiş bir sürüm yoksa) gerçekleşen bir derleme adımı vardır ve işte o zaman hatanızı alırsınız, tam olarak değil kodunuz çalışıyor.

Derleme adımını erteleyebilir ve yukarıda belirtildiği gibi eval kullanarak, tek bir kod satırı için çalışma zamanında gerçekleşmesini sağlayabilirsiniz, ancak kişisel olarak bunu yapmaktan kaçınmayı tercih ederim, çünkü Python'un potansiyel olarak çalışmasına neden olur gereksiz çalışma zamanı derlemesi, bir şey için, diğeri için, kod karmaşası gibi hissettirdiğim şeyi yaratır. (İsterseniz, kod üreten kod üreten kod oluşturabilirsiniz - ve kesinlikle muhteşem bir zaman değiştirme ve hata ayıklama şimdi 6 ay içinde.) Yani ne tavsiye ederim bunun yerine daha böyle bir şey:

import sys
if sys.hexversion < 0x02060000:
    from my_module_2_5 import thisFunc, thatFunc, theOtherFunc
else:
    from my_module import thisFunc, thatFunc, theOtherFunc

.. yeni bir sözdizimi kullanan tek bir fonksiyonum olsa bile yapardım ve çok kısaydı. (Aslında bu tür işlevlerin sayısını ve boyutunu en aza indirmek için her türlü makul önlemi alırım. İçindeki sözdizimi tek satırıyla ifTrueAElseB (koşul, a, b) gibi bir işlev bile yazabilirim.)

Belirtilmeye değer başka bir şey (henüz kimsenin işaret etmediği için biraz şaşırdım) Python'un önceki sürümleri gibi kodu desteklemiyorsa

value = 'yes' if MyVarIsTrue else 'no'

.. gibi kodu destekledi

value = MyVarIsTrue and 'yes' or 'no'

Üçlü ifadeler yazmanın eski yolu buydu. Henüz Python 3 yüklü değil, ama bildiğim kadarıyla, bu "eski" yol bugün hala çalışıyor, böylece ihtiyacınız varsa yeni sözdizimini kullanmanın buna değip değmeyeceğine kendiniz karar verebilirsiniz. Python'un eski sürümlerinin kullanımını desteklemek için.


2
Ciddi anlamda? Bazı küçük yapıları değiştirebilmeniz için kodunuzu çoğaltın. Yuck. Çok yuck. Ve a and b or cbunun yerine, b if a else ceşdeğer değil; eğer bfalsy olduğunu o üreten, başarısız olur ayerine b.
Chris Morgan

1
Kod çoğaltma önermiyorum, imzaları sürümler arasında değişmeyen sürüme özgü kod için sarma işlevleri oluşturmayı ve bu işlevleri sürüme özgü modüllerde koymayı öneriyorum. Belki 1 ila 5 satır uzunluğundaki fonksiyonlardan bahsediyorum. A ve b veya c'nin b'nin false olarak değerlendirilebileceği durumlarda başka bir c ise b ile aynı olmadığı doğrudur. Bu yüzden common_ops_2_4.py'deki ifAThenBElseC (a, b, c), 1 yerine 2 veya 3 satır uzunluğunda olurdu.
Shavais

2

Aşağıdakileri dosyanızın en üstüne yerleştirin:

import sys

if float(sys.version.split()[0][:3]) < 2.7:
    print "Python 2.7 or higher required to run this code, " + sys.version.split()[0] + " detected, exiting."
    exit(1)

Sonra normal Python koduyla devam edin:

import ...
import ...
other code...

1
oldukça kullanınsys.version_info < (2, 7)
Antti Haapala

@AnttiHaapala bu benim için mükemmel, sys.version_infotürü neden bir tuple ile karşılaştırdığınızı açıklayabilir misiniz ?
jjj

@jjj sys.version_info eskiden bir demetti ; örneğin (2, 4, 6, 'final', 0); sadece Python 3 ve 2.7'de ayrı bir türe dönüştürüldü, ancak yine de tuple ile karşılaştırılabilir.
Antti Haapala

@AnttiHaapala Bu yaklaşımı benimkinden daha çok seviyorum ... teşekkürler!
jml

1

Bence en iyi yol sürümlerden ziyade işlevselliği test etmektir. Bazı durumlarda, bu önemsizdir, diğerlerinde böyle değildir.

Örneğin:

try :
    # Do stuff
except : # Features weren't found.
    # Do stuff for older versions.

Deneme / hariç tutma bloklarını kullanma konusunda yeterince spesifik olduğunuz sürece, tabanlarınızın çoğunu kaplayabilirsiniz.


2
Haklısın. Bunu nasıl yapacağını sordu - bazen Y sürümündeki özellikleri test etmek X sürümündeki bayt kodunu bile derlemez, bu yüzden doğrudan yapılamaz.
orip

1

Sorunu kendim çözmeye çalışırken hızlı bir aramadan sonra bu soruyu buldum ve yukarıdaki önerilerin birkaçına dayanan bir melez buldum.

DevPlayer'ın bir sarmalayıcı komut dosyası kullanma fikrini seviyorum, ancak olumsuz, farklı işletim sistemleri için birden fazla sarmalayıcıyı sürdürmenizdir, bu yüzden sarmalayıcıyı python'a yazmaya karar verdim, ancak aynı temel "exe'yi çalıştırarak sürümü yakala" mantığını kullanıyorum ve bununla geldi.

Bence bu 2.5 ve sonrası için çalışmalı. Linux'ta 2.66, 2.7.0 ve 3.1.2'de ve OS X'te 2.6.1'de test ettim.

import sys, subprocess
args = [sys.executable,"--version"]

output, error = subprocess.Popen(args ,stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()
print("The version is: '%s'"  %error.decode(sys.stdout.encoding).strip("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLMNBVCXZ,.+ \n") )

Evet, son kod çözme / şerit çizgisinin korkunç olduğunu biliyorum, ancak sadece sürüm numarasını hızlı bir şekilde yakalamak istedim. Bunu daraltacağım.

Şimdilik bu benim için yeterince işe yarıyor, ama eğer birisi onu geliştirebilirse (veya bana neden korkunç bir fikir olduğunu söyleyebilirse) bu da havalı olurdu.


1

Tek başına python komut dosyaları için, bir python sürümünü (burada v2.7.x) zorlamak için aşağıdaki modül docstring hilesi çalışır (* nix üzerinde test edilmiştir).

#!/bin/sh
''''python -V 2>&1 | grep -q 2.7 && exec python -u -- "$0" ${1+"$@"}; echo "python 2.7.x missing"; exit 1 # '''

import sys
[...]

Bu, eksik python çalıştırılabilirini de işlemelidir, ancak grep'e bağımlıdır. Arka plan için buraya bakın .


0

Sen ile kontrol edebilirsiniz sys.hexversionveya sys.version_info.

sys.hexversioninsan dostu değildir çünkü onaltılık bir sayıdır. sys.version_infobir tuple, bu yüzden daha insan dostu.

Python 3.6 veya daha yenisini kontrol edin sys.hexversion:

import sys, time
if sys.hexversion < 0x30600F0:
    print("You need Python 3.6 or greater.")
    for _ in range(1, 5): time.sleep(1)
    exit()

Python 3.6 veya daha yenisini kontrol edin sys.version_info:

import sys, time
if sys.version_info[0] < 3 and sys.version_info[1] < 6:
    print("You need Python 3.6 or greater.")
    for _ in range(1, 5): time.sleep(1)
    exit()

sys.version_infodaha insan dostudur, ancak daha fazla karakter gerektirir. Daha sys.hexversionaz insan dostu olmasına rağmen öneriyoruz .

Umarım bu sana yardımcı olmuştur!


0

Akhan'ın Python betiği bile derlenmeden önce yararlı bir mesaj yazdıran mükemmel cevabını genişletiyorum .

Betiğin Python 3.6 veya daha yeni bir sürümle çalıştırıldığından emin olmak istiyorsanız, bu iki satırı Python betiğinizin üstüne ekleyin:

#!/bin/sh
''''python3 -c 'import sys; sys.exit(sys.version_info < (3, 6))' && exec python3 -u -- "$0" ${1+"$@"}; echo 'This script requires Python 3.6 or newer.'; exit 1 # '''

(Not: İkinci satır dört tek tırnakla başlar ve üç tek tırnakla biter . Bu garip görünebilir, ancak yazım hatası değildir.)

Bu çözümün avantajı, 3.6'dan daha eski bir Python sürümü kullanıldığında gibi kodun print(f'Hello, {name}!')neden olmayacağıdır SyntaxError. Bunun yerine bu yararlı mesajı göreceksiniz:

This script requires Python 3.6 or newer.

Tabii ki, bu çözüm yalnızca Unix benzeri kabuklarda ve yalnızca komut dosyası doğrudan çağrıldığında (örneğin ./script.py:) ve uygun eXecute izin bitleri ayarlandığında çalışır.


-2

Buna ne dersin:

import sys

def testPyVer(reqver):
  if float(sys.version[:3]) >= reqver:
    return 1
  else:
    return 0

#blah blah blah, more code

if testPyVer(3.0) == 1:
  #do stuff
else:
  #print python requirement, exit statement

5
-1: Güncellenmiş soruda açıklandığı gibi bu işe yaramıyor. Python'un daha yeni bir sürümünden herhangi bir sözdizimi kullanırsanız, dosyanız derlenmez ve derlenmezse sürümü çalıştıramaz ve kontrol edemez!
Scott Griffiths

-3

Sorun oldukça basit. Versiyonuydu eğer kontrol altında , 2.4 az veya hiç eşit . Python sürümü 2.4 ise 2.4'ten az değildir. Sahip olmanız gereken şey:

    if sys.version_info **<=** (2, 4):

, değil

    if sys.version_info < (2, 4):

4
paragraf 3'ü ve güncellemeyi okuyun. yeni dil yapılarını kullanıyorsanız kodunuz 2.4'te derlenmeyeceğinden bu kodu yürütme noktasına gelmezsiniz.
Mark Harrison

Daha az iyiydi, sadece eval eksik.
Craig
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.