Python setattr 与 __setattr__ UnicodeEncodeError
Python setattr vs __setattr__ UnicodeEncodeError
我知道当我们在对象之外时,我们必须使用 setattr
方法。但是,我在使用 unicode 密钥调用 setattr
时遇到问题导致我直接使用 __setattr__
。
class MyObject(object):
def __init__(self):
self.__dict__["properties"] = dict()
def __setattr__(self, k, v):
self.properties[k] = v
obj = MyObject()
然后我得到 obj.properties
的以下内容:
setattr(obj, u"é", u"à")
:引发 UnicodeEncodeError
setattr(obj, "é", u"à")
: {'\xc3\xa9': u'\xe0'}
obj.__setattr__(u"é", u"à")
: {u'\xe9': u'\xe0'}
我不明白为什么 Python 会表现出这些差异
Python2.7?仅 Ascii 标识符。这包括您在 2) 中的代码 - ascii 重音但不包括 .1) - unicode 重音。
Unicode identifiers in Python?
3) 涉及在字典中设置 unicode key。合法的。
请注意,__setattr__ 几乎从不 用于您正在做的事情。它旨在为对象设置属性。不要拦截它并将它们填充到内部 dict 属性中。我也会避免将属性作为名称,与 get/Set 意义上的属性混淆。
通常您想使用 setattr,而不是双下划线变体。不像你的开场白。
您通常也不会调用 双下划线方法,您定义它们并且Python 的底层数据协议代表您调用它们。有点像 JavaBeans get/set 隐式调用(我认为)。
__setattr__ 可能很棘手。如果您不小心,它会以意想不到的方式阻止 "setting activities"。
这是一个愚蠢的例子,
class Foo(object):
def __setattr__(self, attrname, value):
""" let's uppercase variables starting with k"""
if attrname.lower().startswith("k"):
self.__dict__[attrname.upper()] = value
foo = Foo()
foo.kilometer = 1000
foo.meter = 1
print "foo.KILOMETER:%s" % getattr(foo, "KILOMETER", "unknown")
print "foo.meter:%s" % getattr(foo, "meter", "unknown")
print "foo.METER:%s" % getattr(foo, "METER", "unknown")
输出:
foo.KILOMETER:1000
foo.meter:unknown
foo.METER:unknown
您需要在 if
之后添加一个 else
:
else:
self.__dict__[attrname] = value
输出:
foo.KILOMETER:1000
foo.meter:1
foo.METER:unknown
最后,如果您刚刚起步并且 unicode 很重要,我会评估 Python 2 vs 3 - 3 具有更好、统一的 unicode 支持。您可能需要或不需要使用 2.7 而不是 3 的原因有很多,但 unicode "pushes towards" 3.
Python 2 不允许 unicode 标识符:
>>> é = 3
File "<stdin>", line 1
é = 3
^
SyntaxError: invalid syntax
大概它在这一点上非常坚持,以至于您无法在尝试时解决它,因为 setattr
在调用 __setattr__
之前经过了一些处理。您可以通过在 __setattr__
的开头插入 print
来显示这一点:没有打印任何内容,因此问题不在您的代码中。
我知道当我们在对象之外时,我们必须使用 setattr
方法。但是,我在使用 unicode 密钥调用 setattr
时遇到问题导致我直接使用 __setattr__
。
class MyObject(object):
def __init__(self):
self.__dict__["properties"] = dict()
def __setattr__(self, k, v):
self.properties[k] = v
obj = MyObject()
然后我得到 obj.properties
的以下内容:
setattr(obj, u"é", u"à")
:引发 UnicodeEncodeErrorsetattr(obj, "é", u"à")
:{'\xc3\xa9': u'\xe0'}
obj.__setattr__(u"é", u"à")
:{u'\xe9': u'\xe0'}
我不明白为什么 Python 会表现出这些差异
Python2.7?仅 Ascii 标识符。这包括您在 2) 中的代码 - ascii 重音但不包括 .1) - unicode 重音。
Unicode identifiers in Python?
3) 涉及在字典中设置 unicode key。合法的。
请注意,__setattr__ 几乎从不 用于您正在做的事情。它旨在为对象设置属性。不要拦截它并将它们填充到内部 dict 属性中。我也会避免将属性作为名称,与 get/Set 意义上的属性混淆。
通常您想使用 setattr,而不是双下划线变体。不像你的开场白。
您通常也不会调用 双下划线方法,您定义它们并且Python 的底层数据协议代表您调用它们。有点像 JavaBeans get/set 隐式调用(我认为)。
__setattr__ 可能很棘手。如果您不小心,它会以意想不到的方式阻止 "setting activities"。
这是一个愚蠢的例子,
class Foo(object):
def __setattr__(self, attrname, value):
""" let's uppercase variables starting with k"""
if attrname.lower().startswith("k"):
self.__dict__[attrname.upper()] = value
foo = Foo()
foo.kilometer = 1000
foo.meter = 1
print "foo.KILOMETER:%s" % getattr(foo, "KILOMETER", "unknown")
print "foo.meter:%s" % getattr(foo, "meter", "unknown")
print "foo.METER:%s" % getattr(foo, "METER", "unknown")
输出:
foo.KILOMETER:1000
foo.meter:unknown
foo.METER:unknown
您需要在 if
之后添加一个 else
:
else:
self.__dict__[attrname] = value
输出:
foo.KILOMETER:1000
foo.meter:1
foo.METER:unknown
最后,如果您刚刚起步并且 unicode 很重要,我会评估 Python 2 vs 3 - 3 具有更好、统一的 unicode 支持。您可能需要或不需要使用 2.7 而不是 3 的原因有很多,但 unicode "pushes towards" 3.
Python 2 不允许 unicode 标识符:
>>> é = 3
File "<stdin>", line 1
é = 3
^
SyntaxError: invalid syntax
大概它在这一点上非常坚持,以至于您无法在尝试时解决它,因为 setattr
在调用 __setattr__
之前经过了一些处理。您可以通过在 __setattr__
的开头插入 print
来显示这一点:没有打印任何内容,因此问题不在您的代码中。