2015-05-28 12 views
8

Tôi đang gặp sự cố khi chỉ định chuỗi unicode làm tên cho một tệp có tên. Đây hoạt động:được đặt têntuple với chuỗi unicode là tên

a = collections.namedtuple("test", "value") 

và điều này không:

b = collections.namedtuple("βαδιζόντων", "value") 

tôi nhận được lỗi

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib64/python3.4/collections/__init__.py", line 370, in namedtuple 
     result = namespace[typename] 
KeyError: 'βαδιζόντων' 

Tại sao là trường hợp? Tài liệu nói, "Python 3 cũng hỗ trợ sử dụng các ký tự Unicode trong mã định danh" và khóa là unicode hợp lệ?

+1

Something tôi nhận thấy: Nó hoạt động tốt nếu tôi bỏ qua '' ó''. Có vẻ như một lỗi đối với tôi. – pmos

+0

Thú vị - Tôi nên tự mình thử nghiệm. ó là ký tự duy nhất từ ​​khối unicode "Greek Extended", vì vậy điều này có thể có liên quan. Nhưng nó vẫn sẽ không đồng ý với những gì tài liệu nói. – Thomas

+0

Sau khi kiểm tra chặt chẽ hơn, những gì xảy ra là, đối với một số lý do, '' 'ó''' là' '' \ XE1 \ xbd \ xb9''' trong file nguồn UTF-8 mã hóa, nhưng biến thành'' '\ xcf \ x8c''' trong mã được tạo bởi '' namedtuple'' để tạo ra lớp của nó. Điều này chắc chắn có vẻ giống như một lỗi. – pmos

Trả lời

4

Vấn đề đặc biệt với chữ cái (U + 1F79 chữ cái omicron Hy Lạp nhỏ có oxia). Đây là một 'tính tương thích': Unicode thay vì bạn sử dụng ό để thay thế (U + 03CC chữ cái Hy Lạp nhỏ bằng chữ cái omicron). U + 1F79 chỉ tồn tại trong Unicode để đi vòng quanh các bộ ký tự cũ phân biệt giữa oxia và tonos, một sự phân biệt mà sau này hóa ra là không chính xác.

Khi bạn sử dụng các ký tự tương thích trong số nhận dạng, trình phân tích cú pháp mã nguồn của Python sẽ tự động bình thường hóa chúng thành NFKC, do đó tên lớp của bạn kết thúc bằng U + 03CC trong đó.

Thật không may collections.namedtuple không biết về điều này. Cách nó tạo ra cá thể lớp mới là bằng cách chèn tên đã cho vào một bó mã Python trong một chuỗi, sau đó exec uting nó (yuck, phải không?), Và giải nén lớp từ kết quả địa phương dict bằng cách sử dụng tên của nó ... tên gốc, không phải là phiên bản chuẩn hóa mà Python đã thực sự biên dịch, vì vậy nó không thành công.

Đây là lỗi trong collections có thể đáng để nộp đơn, nhưng hiện tại bạn nên sử dụng ký tự chuẩn U + 03CC ό.

+0

Arrg, bây giờ tôi hiểu! Tôi đã bị các ký tự tương thích này cắn vào các chữ cái có dấu của Hy Lạp một số lần. Ít nhất điều đó cho phép tôi giải quyết vấn đề. Cảm ơn bạn đã giải thích của bạn! – Thomas

+0

Một tham chiếu đến mã nguồn sẽ hữu ích https://hg.python.org/cpython/file/661cdbd617b8/Lib/collections/__init__.py#l332 – Kasramvd

2

Điều đó ó là U + 1F79 ɢʀᴇᴇᴋ sᴍᴀʟʟ ʟᴇᴛᴛᴇʀ ᴏᴍɪᴄʀᴏɴ ᴡɪᴛʜ ᴏxɪᴀ. Các mã nhận diện Python được chuẩn hóa như NFKC và U + 1F79 trong NFKC trở thành U + 03CC ɢʀᴇᴇᴋ sᴍᴀʟʟ ʟᴇᴛᴛᴇʀ ᴏᴍɪᴄʀᴏɴ ᴡɪᴛʜ ᴛᴏɴᴏ.

Thật thú vị, nếu bạn sử dụng cùng một chuỗi với U + 1F79 thay thế bằng U + 03CC, nó hoạt động.

>>> b = collections.namedtuple("βαδιζ\u03CCντων", "value") 
>>> 

Tài liệu dành cho namedtuple tuyên bố rằng "Mọi mã nhận dạng Python hợp lệ đều có thể được sử dụng cho tên trường". Cả hai chuỗi là các mã nhận dạng Python hợp lệ, vì có thể dễ dàng được kiểm tra trong trình thông dịch.

>>> βαδιζόντων = 0 
>>> βαδιζόντων = 0 
>>> 

này chắc chắn là một lỗi trong việc thực hiện. Tôi bắt nguồn từ nó để bit này trong việc thực hiện namedtuple:

namespace = dict(__name__='namedtuple_%s' % typename) 
exec(class_definition, namespace) 
result = namespace[typename] # here! 

Tôi đoán rằng typename còn lại trong từ điển namespace bởi exec'ing các class_definition mẫu, là một định danh Python, sẽ là ở dạng NFKC, và do đó không còn khớp với giá trị thực tế của biến số typename được sử dụng để truy lục biến đó. Tôi tin rằng chỉ cần pre-normalizing typename nên sửa lỗi này, nhưng tôi đã không thử nghiệm nó.

+0

Cảm ơn bạn, tôi sẽ vệ sinh đầu vào của tôi và hy vọng điều tốt nhất! – Thomas

1

Althoug có đã là một câu trả lời được chấp nhận cho tôi đưa ra một Fix

của vấn đề

# coding: utf-8 
import collections 
import unicodedata 


def namedtuple_(typename, field_names, verbose=False, rename=False): 
    ''' just like collections.namedtuple(), but does unicode nomalization 
     on names 
    ''' 

    if isinstance(field_names, str): 
     field_names = field_names.replace(',', ' ').split() 
    field_names = [ 
     unicodedata.normalize('NFKC', name) for name in field_names] 
    typename = unicodedata.normalize('NFKC', typename) 

    return collections.namedtuple(
     typename, field_names, verbose=False, rename=False) 


βαδιζόντων = namedtuple_('βαδιζόντων', 'value') 

a = βαδιζόντων(1) 

print(a) 
# βαδιζόντων(value=1) 
print(a.value == 1) 
# True 

nó làm gì?

sử dụng này namedtuple_() triển khai thực hiện chuẩn hóa tên trước giao cho họ collections.namedtuple(), có thể có tên đồng dư.

Đây là một xây dựng trên @R. Ý tưởng của Martinho Fernandes về tiền đề cử tên tuổi.

+0

Cảm ơn bạn, đó là cực kỳ hữu ích! Tôi nghi ngờ nó sẽ không giải quyết trường hợp sử dụng cụ thể của tôi (trong đó bao gồm chiết xuất một danh sách các từ từ một tập tin văn bản và so sánh nó với một danh sách các từ được biết đến), nhưng nó rất tốt để có! – Thomas

+0

nó có thể giúp đỡ, phụ thuộc vào cách/tại sao bạn so sánh nó ... bạn có thể kết hợp dải chracters từ mẫu NFKC với một regexp và có thể hoàn thành toàn bộ nomalization với một thấp hơn() – knitti

Các vấn đề liên quan