ฉันจะตรวจสอบเวอร์ชั่น Python ในโปรแกรมที่ใช้คุณสมบัติภาษาใหม่ได้อย่างไร?


239

หากฉันมีสคริปต์ Python ที่ต้องการ Python อย่างน้อยหนึ่งรุ่นวิธีที่ถูกต้องในการทำให้ล้มเหลวคืออะไรเมื่อใช้ Python เวอร์ชันก่อนหน้าเพื่อเริ่มต้นสคริปต์

ฉันจะควบคุมได้เร็วพอที่จะออกข้อความแสดงข้อผิดพลาดและออกได้อย่างไร

ตัวอย่างเช่นฉันมีโปรแกรมที่ใช้ตัวดำเนินการ ternery (ใหม่ใน 2.5) และ "with" blocks (ใหม่ใน 2.6) ฉันเขียนรูทีนตัวตรวจสอบรุ่นล่ามเล็ก ๆ ง่ายๆซึ่งเป็นสิ่งแรกที่สคริปต์จะเรียก ... ยกเว้นว่ามันจะไปได้ไกลขนาดนั้น แต่สคริปต์ล้มเหลวในระหว่างการรวบรวมหลามก่อนที่ฉันจะเรียกรูทีน ดังนั้นผู้ใช้งานของสคริปต์จึงเห็นข้อผิดพลาดในการติดตามข้อผิดพลาดของ synax ที่ค่อนข้างคลุมเครือซึ่งค่อนข้างต้องใช้ผู้เชี่ยวชาญในการอนุมานว่าเป็นเพียงการเรียกใช้ Python เวอร์ชันผิด

ฉันรู้วิธีตรวจสอบเวอร์ชั่นของ Python ปัญหาคือไวยากรณ์บางอย่างผิดกฎหมายใน Python เวอร์ชันเก่า พิจารณาโปรแกรมนี้:

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 ฉันต้องการผลลัพธ์นี้

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

และไม่ใช่ผลลัพธ์นี้:

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

(Channeling สำหรับผู้ร่วมงาน)


3
"ตรวจสอบเวอร์ชั่นของไพ ธ อนปัญหาคือไวยากรณ์บางตัวผิดกฎหมายในไพ ธ อนรุ่นเก่า" ฉันไม่เข้าใจว่าปัญหานี้เป็นอย่างไร หากคุณสามารถตรวจสอบรุ่นคุณสามารถหลีกเลี่ยงข้อผิดพลาดทางไวยากรณ์ การตรวจสอบเวอร์ชั่นไม่ใช้กับไวยากรณ์อย่างไร คุณช่วยชี้แจงคำถามของคุณได้ไหม?
S.Lott

4
@ S.Lott ไม่คุณไม่ผิดมันเป็นเพียงความยากลำบากในการรวมรหัสบางแห่งที่มันจะไม่ถูกอ่าน (แยกวิเคราะห์) และไม่ถูกดำเนินการ - นี่ไม่ชัดเจนทันทีที่คำตอบปรากฏขึ้น
Brendan

7
S.Lott คุณไม่สามารถทำการทดสอบของคุณในเวอร์ชั่นเก่าของไพ ธ อนเพราะมันไม่ได้รวบรวม คุณจะได้รับข้อผิดพลาดทางไวยากรณ์ทั่วไปแทน ลองใช้โค้ดตัวอย่างพร้อมกับล่าม 2.4 และคุณจะเห็นว่าคุณไม่สามารถทดสอบเวอร์ชันได้
มาร์คแฮร์ริสัน

7
@ S.Lott ขึ้นอยู่กับสิ่งที่คุณพิจารณาว่าไม่สำคัญ - โดยส่วนตัวแล้วฉันจะไม่พิจารณาสร้างไฟล์แยกต่างหากสำหรับ Python รุ่นต่าง ๆ หรือวางไข่กระบวนการพิเศษเล็กน้อย ฉันจะบอกว่าคำถามนี้มีค่าโดยเฉพาะอย่างยิ่งเมื่อคุณคิดว่า Python เต็มไปด้วยเทคนิคที่ประณีตและน่าประหลาดใจบ่อยครั้ง - ฉันมาที่นี่จาก Google และต้องการทราบว่ามีคำตอบที่เป็นระเบียบหรือไม่
Brendan

7
ฉันคิดว่าเราสิ้นสุดการสนทนานี้แล้ว ฉันถามคำถามเกี่ยวกับสิ่งที่ฉันไม่รู้ว่าต้องทำอย่างไรและได้รับคำตอบที่บอกให้ฉันรู้ว่าต้องทำอย่างไร ฉันไม่ได้เสนออะไรเลยฉันแค่ยอมรับคำตอบของ orip ที่ใช้งานได้ดีสำหรับฉัน (อันที่จริงผู้ร่วมงานที่ฉันกำลังแชแนล) Viva Le Stack มากเกิน!
Mark Harrison

คำตอบ:


111

คุณสามารถทดสอบโดยใช้eval:

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

นอกจากนี้ยังwith เป็นที่มีอยู่ใน Python 2.5 from __future__ import with_statementเพียงเพิ่ม

แก้ไข: เพื่อให้สามารถควบคุมได้เร็วคุณสามารถแยกมันออกเป็น.pyไฟล์ต่าง ๆและตรวจสอบความเข้ากันได้ในไฟล์หลักก่อนที่จะนำเข้า (เช่นใน__init__.pyแพ็คเกจ):

# __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
นี่คือคำตอบที่ยอดเยี่ยม ปัญหาหลักจากคำถามที่จำเป็นต้องกำหนดที่อยู่ก็คือโปรแกรมจะต้องแก้ไขให้ถูกต้องสำหรับเวอร์ชันของไพ ธ อนเพื่อเริ่มดำเนินการดังนั้นการใช้ซินแท็กซ์ใหม่จะทำให้โปรแกรมไม่สามารถเริ่มต้นล่ามเวอร์ชันเก่าได้ งาน eval รอบ ๆ ที่
Autoplectic

7
หากแพ็กเกจกำลังถูกติดตั้งโดย setuptools การคอมไพล์ด้วยไบต์ไฟล์ต้นฉบับจะล้มเหลว นอกจากนี้ความเกี่ยวข้องทั้งหมดในการสร้างข้อความแสดงข้อผิดพลาดรันไทม์ดูเหมือนไม่มีจุดหมายเล็กน้อย - ทำไมไม่เพียงทำเอกสารข้อกำหนดและปล่อยให้เป็นเช่นนั้น
John Machin

2
โปรดทราบว่าถ้าพยายามที่จะตรวจสอบการแสดงออกมากกว่าคำสั่งง่ายๆคุณจะต้องใช้แทนexec evalฉันมีสิ่งนี้เกิดขึ้นขณะที่พยายามเขียนฟังก์ชั่นที่จะพิมพ์ไปยัง stderr ทั้ง py2k และ py3k
Xiong Chiamiov

2
ผมคิดว่าเป็นรุ่นที่ทำความสะอาดของการแก้ปัญหานี้จะเป็นที่จะนำ "การตรวจสอบ" ของคุณในโมดูลที่แยกต่างหากและนำเข้าที่ (ห่อimportสถานีลอง / ยกเว้น) โปรดทราบว่าคุณอาจจำเป็นต้องตรวจสอบสิ่งอื่นนอกเหนือจากนี้SyntaxErrorเช่นกัน (เช่นฟังก์ชัน builtin หรือส่วนเพิ่มเติมในไลบรารีมาตรฐาน)
Steven

103

มี wrapper รอบโปรแกรมของคุณที่ทำต่อไปนี้

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()หากคุณวางแผนที่จะพบกับคนที่ใช้ pre-2.0 Python interpreters แต่คุณต้องมีนิพจน์ทั่วไปที่ต้องทำ

และอาจมีวิธีที่สง่างามกว่าในการทำเช่นนี้


7
FYI, "cur_version> = req_version" ควรทำงานตามเงื่อนไข
orip

4
sys.version_infoไม่ใช่ฟังก์ชั่น
nh2

3
การวางโค้ดไว้ในเงื่อนไขที่ประสบความสำเร็จเช่นนั้นเป็นการฝึกที่แย่มากเพราะเป็นการเยื้องที่ไม่จำเป็นและการเพิ่มตรรกะ เพียงทำ: ถ้า sys.version_info [: 2] <req_version: พิมพ์ "เก่า"; sys.exit () - และดำเนินการต่อตามปกติ
timss

1
มันเหมือนกับที่ Tim Peters พูดไว้ใน "The Zen of Python": "Flat ดีกว่าซ้อนกัน" (คุณสามารถดูสิ่งนี้ได้โดยพิมพ์ "import this" ใน python)
Christopher Shroba

1
@ChristopherShroba import thisขอขอบคุณสำหรับ เกมที่น่ารัก
ซามูเอลฮาร์เมอร์

32

ลอง

แพลตฟอร์มนำเข้า
platform.python_version ()

ควรให้สตริงเช่น "2.3.1" หากไม่ตรงกับที่คุณต้องการมีชุดข้อมูลจำนวนมากที่มีอยู่ในตัว "แพลตฟอร์ม" สิ่งที่คุณต้องการควรจะอยู่ที่นั่นที่ไหนสักแห่ง


4
-1: วิธีนี้ใช้ไม่ได้ดังที่อธิบายไว้ในคำถามที่อัปเดตแล้ว ถ้าคุณใช้ซินแท็กซ์ใด ๆ จาก Python เวอร์ชั่นใหม่กว่าไฟล์ของคุณจะไม่คอมไพล์และถ้ามันไม่คอมไพล์ก็จะไม่สามารถรันและตรวจสอบเวอร์ชั่นได้!
Scott Griffiths

1
@ScottGriffiths เรียกใช้print(platform.python_version())แทนplatform.python_version()!
Suriyaa

@ScottGriffiths และชำระเงินคำตอบของฉัน: stackoverflow.com/a/40633458/5157221
Suriyaa

22

sys.hexversionน่าจะเป็นวิธีที่ดีที่สุดที่จะทำทำเปรียบเทียบรุ่นนี้คือการใช้ สิ่งนี้มีความสำคัญเนื่องจากการเปรียบเทียบรุ่นทูเปิลจะไม่ให้ผลลัพธ์ที่ต้องการในเวอร์ชันไพ ธ อนทั้งหมด

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

ฉันคิดว่านี่เป็นสิ่งที่งดงามที่สุด แต่อาจไม่ใช่วิธีที่ง่ายที่สุดในการเข้าใจโดยผู้พัฒนารายอื่น
Nick Bolton

5
คุณสามารถอธิบายได้ว่าในสถานการณ์ใดที่การเปรียบเทียบรุ่น tuples จะไม่ให้ผลลัพธ์ที่ต้องการ?
SpoonMeiser

tuples เวอร์ชันสามารถมีค่าตัวอักษรและตัวเลขได้เช่นกัน
โซริน

8
-1: วิธีนี้ใช้ไม่ได้ดังที่อธิบายไว้ในคำถามที่อัปเดตแล้ว ถ้าคุณใช้ซินแท็กซ์ใด ๆ จาก Python เวอร์ชั่นใหม่กว่าไฟล์ของคุณจะไม่คอมไพล์และถ้ามันไม่คอมไพล์ก็จะไม่สามารถรันและตรวจสอบเวอร์ชั่นได้!
Scott Griffiths

เวอร์ชัน / แพลตฟอร์มใดที่ล้มเหลว
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
พึงระวังว่าใน Python 2.6 หรือต่ำกว่าsys.version_infoนั้นไม่ใช่ tuple ที่มีชื่อ คุณจะต้องใช้sys.version_info[0]สำหรับหมายเลขเวอร์ชันหลักและsys.version_info[1]สำหรับรุ่นรอง
coredumperror

9

คำตอบจาก Nykakin ที่AskUbuntu :

นอกจากนี้คุณยังสามารถตรวจสอบเวอร์ชั่น Python จากโค้ดเองโดยใช้platformโมดูลจากไลบรารีมาตรฐาน

มีสองฟังก์ชั่น:

  • platform.python_version() (ส่งคืนสตริง)
  • platform.python_version_tuple() (ส่งคืน tuple)

รหัสหลาม

สร้างไฟล์ตัวอย่างเช่น: version.py)

วิธีง่ายๆในการตรวจสอบเวอร์ชั่น:

import platform

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

คุณยังสามารถใช้evalวิธีการ:

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

เรียกใช้ไฟล์ Python ในบรรทัดคำสั่ง:

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

ผลลัพธ์ของ Python กับ CGI ผ่าน WAMP Server บน Windows 10:

ภาพหน้าจอ 2016-11-16 14.39.01 โดย Suriyaa Kudo


ทรัพยากรที่มีประโยชน์


7

ชุดกลายเป็นส่วนหนึ่งของภาษาหลักใน Python 2.4 เพื่อให้สามารถใช้งานร่วมกันได้ ฉันทำสิ่งนี้ย้อนกลับไปแล้วซึ่งจะได้ผลกับคุณเช่นกัน:

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

3
ดีกว่าที่จะตรวจสอบคุณสมบัติแทนรุ่นใช่ไหม try: set except NameError: from sets import Set as set
orip

@orip: ทำไม หากคุณรู้ว่าฟีเจอร์ใดที่มีการเปิดตัวเช่นชุดที่นี่เพียงใช้โค้ดด้านบน ไม่มีอะไรผิดปกติกับที่
André

7

แม้ว่าคำถามคือ: ฉันจะควบคุมได้เร็วพอที่จะออกข้อความแสดงข้อผิดพลาดและออกได้อย่างไร

คำถามที่ฉันตอบคือ: ฉันจะควบคุมได้เร็วพอที่จะออกข้อความแสดงข้อผิดพลาดก่อนเริ่มแอพได้อย่างไร

ฉันสามารถตอบได้มากแตกต่างจากโพสต์อื่น ๆ ดูเหมือนว่าคำตอบจะพยายามแก้ไขคำถามของคุณจากภายใน Python

ผมว่าให้ทำการตรวจสอบเวอร์ชั่นก่อนเปิดตัว Python ฉันเห็นเส้นทางของคุณคือ Linux หรือ Unix อย่างไรก็ตามฉันสามารถเสนอสคริปต์ Windows ให้คุณเท่านั้น ฉันอิมเมจปรับให้เหมาะกับการสร้างสคริปต์ลินุกซ์จะไม่ยากเกินไป

นี่คือสคริปต์ DOS พร้อมกับรุ่น 2.7:

@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

สิ่งนี้ไม่ได้รันส่วนใด ๆ ของแอปพลิเคชันของคุณและดังนั้นจะไม่เพิ่มข้อยกเว้น Python มันไม่ได้สร้างไฟล์ชั่วคราวหรือเพิ่มตัวแปรสภาพแวดล้อมระบบปฏิบัติการใด ๆ และจะไม่จบแอปของคุณเป็นข้อยกเว้นเนื่องจากกฎไวยากรณ์เวอร์ชันที่แตกต่างกัน นั่นเป็นจุดเข้าถึงที่ปลอดภัยน้อยที่สุดสามจุด

FOR /Fบรรทัดเป็นกุญแจสำคัญ

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

สำหรับรุ่นหลามหลายรุ่นลองดู url: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

และเวอร์ชั่นแฮ็คของฉัน:

[สคริปต์ MS; Python ตรวจสอบเวอร์ชั่นก่อนเปิดตัวโมดูล Python] http://pastebin.com/aAuJ91FQ


สำหรับคะแนนโหวตเหล่านั้นโปรดอย่ากลัวที่จะอธิบายเหตุผลว่าทำไม
DevPlayer

ฉันกำลังมองหาอย่างแน่นอน ขอบคุณ! %% H คืออะไร
Clocker

@Clocker python.exe -V จะส่งคืนสตริง "Python 2.7" คอนโซลใส่สตริง "Python" ลงใน %% G และสตริง "2.7" ใน os var %% H ที่สร้างขึ้นโดยอัตโนมัติ (ตัวอักษรถัดไปหลัง G) สะท้อน %% H | ค้นหา "2.7" pipes "2.7" ในคำสั่ง DOS ค้นหา "2.7" ซึ่งตั้งค่าระดับความผิดพลาดเป็น 1 หากพบ %% H ใน "2.7" ระดับข้อผิดพลาดนั้นส่งผลให้ 1 จากการใช้คำสั่ง DOS find จะช่วยให้เราสามารถแยกไปที่ป้ายแบตช์ DOS: Python27
DevPlayer

3
import sys
sys.version

จะได้รับคำตอบเช่นนี้

'2.7.6 (ค่าเริ่มต้น 26 ตุลาคม 2559, 20:30:19) \ n [GCC 4.8.4]'

ที่นี่2.7.6เป็นรุ่น


2

ดังที่ระบุไว้ข้างต้นข้อผิดพลาดทางไวยากรณ์เกิดขึ้น ณ เวลารวบรวมไม่ใช่เวลาทำงาน ในขณะที่ Python เป็น "ภาษาตีความ" รหัส Python ไม่ได้แปลโดยตรงจริงๆ มันรวบรวมไปยังรหัสไบต์ซึ่งถูกตีความแล้ว มีขั้นตอนการคอมไพล์ที่เกิดขึ้นเมื่อโมดูลถูกอิมพอร์ต (หากไม่มีเวอร์ชันที่คอมไพล์แล้วในรูปแบบของไฟล์. pyc หรือ. pyd) และนั่นคือเมื่อคุณได้รับข้อผิดพลาดไม่ใช่ (ค่อนข้างแน่นอน) เมื่อ รหัสของคุณกำลังทำงาน

คุณสามารถเลื่อนขั้นตอนการคอมไพล์และทำให้มันเกิดขึ้น ณ รันไทม์สำหรับโค้ดบรรทัดเดียวหากคุณต้องการโดยใช้ eval ดังที่ได้กล่าวไว้ข้างต้น แต่โดยส่วนตัวแล้วฉันชอบที่จะหลีกเลี่ยงการทำเช่นนั้นเพราะมันทำให้ Python การรวบรวมรันไทม์ที่ไม่จำเป็นสำหรับสิ่งหนึ่งและอีกอย่างหนึ่งมันสร้างสิ่งที่ฉันรู้สึกเหมือนเป็นความยุ่งเหยิงของรหัส (ถ้าคุณต้องการคุณสามารถสร้างรหัสที่สร้างรหัสที่สร้างรหัส - และมีเวลาที่ยอดเยี่ยมในการแก้ไขและแก้ไขจุดบกพร่องใน 6 เดือนนับจากนี้) ดังนั้นสิ่งที่ฉันอยากจะแนะนำแทนคืออะไรเช่นนี้:

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

.. ซึ่งฉันจะทำแม้ว่าฉันจะมีเพียงหนึ่งฟังก์ชันที่ใช้ไวยากรณ์ที่ใหม่กว่าและมันสั้นมาก (อันที่จริงฉันจะใช้ทุกมาตรการที่เหมาะสมเพื่อลดจำนวนและขนาดของฟังก์ชั่นดังกล่าวฉันอาจเขียนฟังก์ชันเช่น ifTrueAElseB (cond, a, b) ด้วยไวยากรณ์บรรทัดเดียวในนั้น)

อีกสิ่งที่อาจคุ้มค่าที่จะชี้ให้เห็น (ที่ฉันประหลาดใจเล็กน้อยที่ยังไม่มีใครชี้ให้เห็น) คือในขณะที่ Python รุ่นก่อนหน้าไม่สนับสนุนรหัสเช่น

value = 'yes' if MyVarIsTrue else 'no'

.. มันสนับสนุนรหัสเช่น

value = MyVarIsTrue and 'yes' or 'no'

นั่นเป็นวิธีเขียนแบบไตรภาค ฉันยังไม่ได้ติดตั้ง Python 3 แต่เท่าที่ฉันรู้ว่าวิธีการ "เก่า" ยังคงใช้ได้จนถึงทุกวันนี้ดังนั้นคุณสามารถตัดสินใจด้วยตัวเองว่าคุ้มหรือไม่ที่จะใช้ไวยากรณ์ใหม่ตามเงื่อนไขถ้าคุณต้องการ เพื่อรองรับการใช้งาน Python เวอร์ชั่นเก่า


2
อย่างจริงจัง? ทำซ้ำรหัสของคุณเพื่อให้คุณสามารถเปลี่ยนโครงสร้างย่อยบางส่วนได้หรือไม่ yuck สวยมาก และสำหรับa and b or cแทนที่จะเป็นb if a else cมันไม่เทียบเท่า; ถ้าbเป็น falsy มันจะล้มเหลว, การผลิตมากกว่าa b
Chris Morgan

1
ฉันไม่แนะนำรหัสซ้ำฉันแนะนำให้สร้างฟังก์ชั่น wrapper สำหรับรหัสเฉพาะรุ่นซึ่งมีลายเซ็นต์ไม่เปลี่ยนแปลงในทุกรุ่นและวางฟังก์ชันเหล่านั้นในโมดูลเฉพาะรุ่น ฉันกำลังพูดถึงฟังก์ชั่นที่อาจมีความยาว 1 ถึง 5 บรรทัด มันเป็นความจริงที่ a และ b หรือ c ไม่เหมือนกับ b ถ้า a อื่น c ในกรณีที่ b อาจประเมินว่าเป็นเท็จ ดังนั้นฉันเดา ifAThenBElseC (a, b, c) ใน common_ops_2_4.py จะต้องมีความยาว 2 หรือ 3 บรรทัดแทนที่จะเป็น 1 วิธีนี้จะช่วยลดรหัสของคุณลงได้โดยการห่อหุ้มสำนวนสามัญให้เป็นหน้าที่
Shavais

2

วางต่อไปนี้ที่ด้านบนสุดของไฟล์ของคุณ:

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)

จากนั้นดำเนินการต่อโดยใช้รหัส Python ปกติ:

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

1
ค่อนข้างใช้sys.version_info < (2, 7)
Antti Haapala

@AnttiHaapala นี้เหมาะสำหรับฉันคุณช่วยอธิบายได้ไหมว่าทำไมการเปรียบเทียบsys.version_infoประเภทกับ tuple ใช้งานได้หรือไม่
jjj

@jjj sys.version_info เคยเป็น tuple; ตัวอย่างเช่น(2, 4, 6, 'final', 0); เฉพาะใน Python 3 และ 2.7 เท่านั้นที่ถูกเปลี่ยนเป็นประเภทแยกซึ่งยังคงเทียบเคียงได้กับสิ่งอันดับ
Antti Haapala

@AnttiHaapala ฉันชอบวิธีการที่ดีกว่าของฉัน ... ขอบคุณ!
jml

1

ฉันคิดว่าวิธีที่ดีที่สุดคือทดสอบการใช้งานมากกว่ารุ่น ในบางกรณีนี่เป็นเรื่องเล็กน้อย

เช่น:

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

ตราบใดที่คุณเฉพาะเจาะจงมากพอในการใช้ลอง / ยกเว้นบล็อกคุณสามารถครอบคลุมฐานส่วนใหญ่ได้


2
คุณถูก. นั่นคือสิ่งที่เขาถามว่าจะทำอย่างไร - บางครั้งการทดสอบคุณสมบัติในเวอร์ชัน Y ไม่ได้คอมไพล์โค้ดไบต์ในเวอร์ชัน X ดังนั้นจึงไม่สามารถทำได้โดยตรง
orip

1

ฉันเพิ่งพบคำถามนี้หลังจากการค้นหาอย่างรวดเร็วในขณะที่พยายามแก้ปัญหาด้วยตัวเองและฉันได้พบลูกผสมตามคำแนะนำข้างต้น

ฉันชอบความคิดของ DevPlayer ในการใช้สคริปต์ wrapper แต่ข้อเสียคือคุณต้องดูแลหลาย wrappers สำหรับ OS ที่แตกต่างกันดังนั้นฉันจึงตัดสินใจเขียน wrapper ในไพ ธ อน แต่ใช้พื้นฐาน "grab the version โดยรัน exe" ตรรกะ และเกิดขึ้นกับสิ่งนี้

ฉันคิดว่ามันควรจะใช้งานได้ 2.5 และต่อไป ฉันได้ทดสอบกับ 2.66, 2.7.0 และ 3.1.2 บน Linux และ 2.6.1 บน OS X แล้ว

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") )

ใช่ฉันรู้ว่าสายถอดรหัส / สตริปสุดท้ายนั้นน่ากลัว แต่ฉันแค่อยากจะคว้าหมายเลขเวอร์ชั่นได้อย่างรวดเร็ว ฉันจะแก้ไขสิ่งนั้น

มันใช้งานได้ดีพอสำหรับฉันตอนนี้ แต่ถ้าใครสามารถปรับปรุงได้


1

สำหรับสคริปต์ python แบบสแตนด์อโลนเคล็ดลับ docstring โมดูลต่อไปนี้เพื่อบังคับใช้ python เวอร์ชัน (ที่นี่ v2.7.x) ทำงาน (ทดสอบบน * nix)

#!/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
[...]

สิ่งนี้ควรจัดการกับไฟล์ไพ ธ อนที่หายไปเช่นกัน แต่มีการพึ่งพา grep ดูที่นี่สำหรับพื้นหลัง


0

คุณสามารถตรวจสอบด้วยหรือsys.hexversionsys.version_info

sys.hexversionไม่เป็นมิตรกับมนุษย์มากเพราะเป็นเลขฐานสิบหก sys.version_infoเป็นทูเปิลจึงเป็นมิตรกับมนุษย์มากกว่า

ตรวจสอบ Python 3.6 หรือใหม่กว่าด้วย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 หรือใหม่กว่าด้วย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_infoเป็นมนุษย์มากขึ้น แต่ใช้ตัวละครมากขึ้น ฉันขอแนะนำsys.hexversionอีกครั้งแม้ว่ามันจะเป็นมิตรกับมนุษย์น้อยกว่าก็ตาม

ฉันหวังว่านี่จะช่วยคุณได้!


0

ฉันกำลังขยายคำตอบที่ยอดเยี่ยมของ akhan ซึ่งพิมพ์ข้อความที่มีประโยชน์ก่อนที่สคริปต์ Python จะถูกรวบรวม

หากคุณต้องการให้แน่ใจว่าสคริปต์จะถูกเรียกใช้ด้วย Python 3.6 หรือใหม่กว่าเพิ่มสองบรรทัดเหล่านี้ไปด้านบนของสคริปต์ Python ของคุณ:

#!/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 # '''

(หมายเหตุ: บรรทัดที่สองเริ่มต้นด้วยเครื่องหมายคำพูดเดี่ยวสี่คำและลงท้ายด้วยเครื่องหมายคำพูดเดี่ยวสามคำซึ่งอาจดูแปลก แต่ไม่ใช่พิมพ์ผิด)

ข้อดีของการแก้ปัญหานี้คือรหัสที่เหมือนprint(f'Hello, {name}!')จะไม่ทำให้ a SyntaxErrorหากใช้ Python เวอร์ชันที่เก่ากว่า 3.6 คุณจะเห็นข้อความที่เป็นประโยชน์นี้แทน:

This script requires Python 3.6 or newer.

แน่นอนวิธีนี้ใช้งานได้กับเชลล์ที่เหมือน Unix เท่านั้นและเมื่อสคริปต์ถูกเรียกใช้โดยตรง (เช่น./script.py:) และมีการตั้งค่าบิตการอนุญาต eXecute ที่เหมาะสม


-2

เกี่ยวกับสิ่งนี้:

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: วิธีนี้ใช้ไม่ได้ดังที่อธิบายไว้ในคำถามที่อัปเดตแล้ว ถ้าคุณใช้ซินแท็กซ์ใด ๆ จาก Python เวอร์ชั่นใหม่กว่าไฟล์ของคุณจะไม่คอมไพล์และถ้ามันไม่คอมไพล์ก็จะไม่สามารถรันและตรวจสอบเวอร์ชั่นได้!
Scott Griffiths

-3

ปัญหาค่อนข้างง่าย คุณตรวจสอบว่ารุ่นคือน้อยกว่า 2.4 ไม่น้อยกว่าหรือเท่ากับ ดังนั้นหากเวอร์ชัน Python คือ 2.4 จะไม่น้อยกว่า 2.4 สิ่งที่คุณควรมีคือ:

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

ไม่ใช่

    if sys.version_info < (2, 4):

4
อ่านย่อหน้า 3 และการอัพเดท คุณไม่ต้องดำเนินการกับรหัสนี้เพราะรหัสของคุณจะไม่รวบรวมใน 2.4 หากคุณใช้โครงสร้างภาษาใหม่
Mark Harrison

น้อยกว่าก็ไม่เป็นไรแค่หาย eval
Craig
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.