2009-02-22 59 views

Trả lời

16

tôi muốn phân tích chuỗi nếu chuyển đổi thất bại:

>>> def convert(s): 
    try: 
     return float(s) 
    except ValueError: 
     num, denom = s.split('/') 
     return float(num)/float(denom) 
... 

>>> convert("0.1234") 
0.1234 

>>> convert("1/2") 
0.5 

Nói chung sử dụng eval là một ý tưởng tồi, vì đó là một nguy cơ bảo mật. Đặc biệt là nếu chuỗi được đánh giá đến từ bên ngoài hệ thống.

+1

+1. eval là hoàn toàn không cần thiết trong trường hợp này, và tôi vui vì ai đó (ngoài tôi, tất nhiên) bị mắc kẹt cho những gì đúng. –

+0

Đánh giá không phải là rủi ro bảo mật trừ khi đồng nghiệp của bạn là những kẻ xã hội độc hại. Bạn không cần nó trong trường hợp này, nhưng nó không còn là một nguy cơ bảo mật hơn so với mã nguồn mở. –

+0

Rất tốt. Các chuỗi thực sự là từ bên ngoài vì vậy tôi cần phải đi an toàn (và cố gắng không để tìm hiểu những thói quen xấu). Tôi đã hy vọng không cần phải phân tích nó nhưng điều này không phải là quá xấu và hoạt động như một say mê. – ketorin

3

Nhà điều hành / không phân chia số nguyên. Hãy thử:

>>> eval("1.0*" + "1/2") 
0.5 

eval() là nguy hiểm, bạn nên luôn luôn kiểm tra một cách chính xác những gì bạn đang đi vào nó:

>>> import re 
>>> s = "1/2" 
>>> if re.match(r"\d+/\d+$", s): 
...  eval("1.0*" + s) 
... 
0.5 

Tuy nhiên, nếu bạn đi đến những rắc rối của phù hợp với đầu vào đối với một regex trong nơi đầu tiên, bạn cũng có thể sử dụng số r"(\d+)/(\d+)$" để trích xuất tử số và mẫu số, tự phân chia và tránh hoàn toàn eval():

>>> m = re.match(r"(\d+)/(\d+)$", s) 
>>> if m: 
...  float(m.group(1))/float(m.group(2)) 
... 
0.5 
+0

Cảm ơn, gợi ý eval là tốt đẹp để bây giờ và sẽ làm công việc chỉ tuyệt vời ... ngoại trừ việc tôi nhận ra tôi cần một giải pháp an toàn như nhọn ngoài. – ketorin

0

Đó là bởi vì 1 và 2 được giải thích bởi Python như số nguyên và không nổi. Nó cần phải là 1.0/2.0 hoặc một số kết hợp đó.

4

Sử dụng from __future__ import division để nhận hành vi bạn muốn. Sau đó, trong một nhúm, bạn có thể làm một cái gì đó như

from __future__ import division 
strings = ["0.1234", "1/2", "2/3"] 
numbers = map(eval, strings) 

để có danh sách nổi trên dây của bạn. Nếu bạn muốn làm điều này theo cách "đúng", không sử dụng eval(), nhưng thay vào đó viết một hàm chấp nhận một chuỗi và gọi float() trên đó nếu nó không chứa dấu gạch chéo hoặc phân tích chuỗi và chia tử số và mẫu số nếu có một dấu gạch chéo trong đó.

Một cách để làm điều đó:

def parse_float_string(x) 
    parts = x.split('/', 1) 
    if len(parts) == 1: 
     return float(x) 
    elif len(parts) == 2: 
     return float(parts[0])/float(parts[1]) 
    else: 
     raise ValueError 

Sau đó chỉ cần map(parse_float_string, strings) sẽ giúp bạn có được danh sách của bạn.

2

Vấn đề với eval là, như trong python, thương số của số nguyên là một số nguyên. Vì vậy, bạn có nhiều lựa chọn.

Đầu tiên là cách đơn giản để làm cho lợi nhuận phân chia số nguyên nổi:

from __future__ import division 

khác là để phân chia các số hợp lý:

reduce(lambda x, y: x*y, map(int, rat_str.split("/")), 1) 

đâu rat_str là chuỗi với một số hợp lý.

0

Đề xuất với from __future__ import division kết hợp với eval chắc chắn sẽ hoạt động.

Có lẽ đáng để chỉ ra rằng các đề xuất không sử dụng eval mà là phân tích cú pháp chuỗi vì vậy eval rất nguy hiểm: nếu có cách nào đó cho một chuỗi tùy ý được gửi đến eval, thì hệ thống của bạn dễ bị tổn thương . Vì vậy, đó là một thói quen xấu. (Nhưng nếu đây chỉ là mã nhanh chóng và bẩn, có thể không phải là rằng một giao dịch lớn!)

7

Như những người khác đã chỉ ra, sử dụng eval có thể là một nguy cơ nguy hiểm. (nếu bạn không nghĩ rằng nó là như rủi ro như exec, hãy tưởng tượng eval ing cái gì đó như: __import__('os').system('rm -rf /'))

Tuy nhiên, nếu bạn có python 2.6 hoặc lên, bạn có thể sử dụng ast.literal_eval, mà chuỗi cung cấp:

chỉ có thể bao gồm các cấu trúc sau: Cấu trúc chữ Python: chuỗi, số, bộ, danh sách, dấu gạch ngang, booleans và Không.

Vì vậy nó nên được khá an toàn :-)

+0

Không biết về điều đó - cảm ơn! –

+0

Làm cách nào để có thể đánh giá thứ gì đó độc hại như ví dụ mà không có đồng nghiệp bị quấy rối nghiêm trọng? Đánh giá không phải là một nguy cơ bảo mật hơn là truy cập vào trình bao là một nguy cơ bảo mật. –

+0

Điểm công bằng .. Nếu bạn không giao dịch với đầu vào không tin cậy thì eval không có rủi ro. Tôi nghĩ rằng tôi bị ảnh hưởng bởi bài đăng này: http://phpxmlrpc.sourceforge.net/#security - PHP guys đã cố gắng hai lần để giải quyết vấn đề của họ, trước khi nhận ra rằng họ đã phải loại bỏ eval. Vì vậy, ... –

6

Một tùy chọn khác (cũng chỉ cho 2,6 trở lên) là module fractions.

>>> from fractions import Fraction 
>>> Fraction("0.1234") 
Fraction(617, 5000) 
>>> Fraction("1/2") 
Fraction(1, 2) 
>>> float(Fraction("0.1234")) 
0.1234 
>>> float(Fraction("1/2")) 
0.5 
1

Trong Python 3, thao tác này sẽ hoạt động.

>>> x = ["0.1234", "1/2"] 
>>> [eval(i) for i in x] 
[0.1234, 0.5] 
+1

Phải, trong Python 3 họ đã làm 'từ __future__ bộ phận nhập khẩu' mặc định ... trong Python 3, tương lai là bây giờ! – kquinn

1

sympy có thể giúp bạn ra ở đây:

import sympy 

half = sympy.Rational('1/2') 
p1234 = sympy.Rational('0.1234') 
print '%f, %f" % (half, p1234) 
Các vấn đề liên quan