Python string.translate引发字符串格式(ddd)ddd dddd的类型错误

Python string.translate引发字符串格式(ddd)ddd dddd的类型错误,python,django,unit-testing,unicode,Python,Django,Unit Testing,Unicode,我需要格式化一些电话号码,我想要的格式是'(ddd)ddd ddddd'。我从别人那里偷了密码,并一如既往地投票支持它。在大多数情况下,它工作得很好,但有一些事情我不明白 我有一个名为CustomerStudent的Django型号,它有一个手机和商务电话字段。我的保存方法: def save(self, *args, **kwargs): self.cell_phone = format_phone(self.cell_phone) self.business_phone =

我需要格式化一些电话号码,我想要的格式是
'(ddd)ddd ddddd'
。我从别人那里偷了密码,并一如既往地投票支持它。在大多数情况下,它工作得很好,但有一些事情我不明白

我有一个名为
CustomerStudent
的Django型号,它有一个
手机
商务电话
字段。我的保存方法:

def save(self, *args, **kwargs):
    self.cell_phone = format_phone(self.cell_phone)
    self.business_phone = format_phone(self.business_phone)
    super(CustomerStudent, self).save(*args, **kwargs)
format\u phone
方法位于我的
util.py
文件中

def format_phone(str=None):
    if str is None:
        return str
    all = string.maketrans('', '')
    nodigs=all.translate(all, string.digits)
    raw_phone = str.translate(all, nodigs)
    if len(raw_phone) == 10:
        pass
    elif len(raw_phone) == 7:
        raw_phone = '000' + raw_phone
    else:
        return None
    return '(%s)%s-%s' % (raw_phone[0:3:1], raw_phone[3:6:1], raw_phone[6::1])
当我遇到这个问题时,我正在编写测试来检查这个模型

使用以下值建立测试模型:

cell_phone = '5555555555'
business_phone = '999-9999'
tests.py

s = CustomerStudent.objects.get(pk=1)
self.assertEqual(s.cell_phone, '(555)555-5555') # Passes
self.assertEqual(s.business_phone, '(000)999-9999') # Passes
s.cell_phone = 'a5-55l7i77(7/7e7p7-)'
s.save()
self.assertEqual(s.cell_phone, '(555)777-7777') # Passes
self.assertEqual(s.business_phone, '(000)999-9999') # Fails
错误提示:

Creating test database for alias 'default'...
.........E............
======================================================================
ERROR: test_customer_student (training.tests.TrainingTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/app/tests.py", line 281, in test_customer_student
s.save()
File "/path/to/app/models.py", line 149, in save
self.business_phone = format_phone(self.business_phone)
File "path/to/app/util.py", line 16, in format_phone
raw_phone = str.translate(all, nodigs)
TypeError: translate() takes exactly one argument (2 given)

----------------------------------------------------------------------
Ran 22 tests in 0.968s

FAILED (errors=1)
Destroying test database for alias 'default'...
我知道Unicode的行为不同,但我确保新电话号码中存在正确格式电话号码中的所有字符。我决定捕获
TypeError
并返回
None

def format_phone(str=None):
    if str is None:
        return str
    all = string.maketrans('', '')
    nodigs=all.translate(all, string.digits)
    try:
        raw_phone = str.translate(all, nodigs)
    except TypeError:
        return None
    if len(raw_phone) == 10:
        pass
    elif len(raw_phone) == 7:
        raw_phone = '000' + raw_phone
    else:
        return None
    return '(%s)%s-%s' % (raw_phone[0:3:1], raw_phone[3:6:1], raw_phone[6::1])
现在,当我运行测试时:

Creating test database for alias 'default'...
.........F............
======================================================================
FAIL: test_customer_student (training.tests.TrainingTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/path/to/app/tests.py", line 283, in  test_customer_student
self.assertEqual(s.business_phone, '(000)999-9999')
AssertionError: None != '(000)999-9999'

----------------------------------------------------------------------
Ran 22 tests in 0.954s

FAILED (failures=1)
Destroying test database for alias 'default'...
现在回答问题。当号码没有改变时,为什么会发生这种情况?我相信它与Unicode有关,但是新的
手机号码
中有相同的字符,并且它可以正确地通过
格式化手机


我可能可以通过检查电话号码是否在保存方法中发生了变化来解决这个问题,但这似乎是可以避免的开销。建议?

您可以强制使用正则字符串:

def format_phone(phone_str=None):
    phone_str = phone_str.encode('ascii', 'ignore')
    [...]

如图所示

您是否尝试在手机的
格式化
功能的开头添加
打印(str,键入(str))
?还有,用
str
作为变量名是个坏主意。为什么这是个坏主意?是保留的吗?哦,现在我明白了,我同意了,我会改变它。谢谢。哦,是的,
format\u phone
返回的是Unicode。