Pra*_*ain 5 python casting class python-2.7
考虑一堂课;
class temp:
def __init__(self):
pass
Run Code Online (Sandbox Code Playgroud)
我以它为对象;
obj = temp()
Run Code Online (Sandbox Code Playgroud)
将其转换为字符串;
strObj = str(obj)
Run Code Online (Sandbox Code Playgroud)
现在,如何将strObj转换为temp类的对象?
org = temp(strObj)
Run Code Online (Sandbox Code Playgroud)
要回答这个问题,一种方法是“滥用”__repr__与eval(). 我们先来看看__repr__文档(重点:我的):
由 repr() 内置函数调用以计算对象的“官方”字符串表示。如果可能的话,这应该看起来像一个有效的 Python 表达式,可用于重新创建具有相同值的对象(给定适当的环境)。如果这是不可能的,则应返回 <...一些有用的描述...> 形式的字符串。返回值必须是字符串对象。如果一个类定义了
__repr__()但没有定义__str__(),则__repr__()在需要该类实例的“非正式”字符串表示时也使用。这通常用于调试,因此表示信息丰富且明确是很重要的。
考虑到这一点,我们知道建议返回一个__repr__可以与eval(). 值“应该看起来像一个有效的 Python 表达式”的语句暗示了这一点。
这是一个使用它的示例。该示例也覆盖了__eq__,但只是为了方便打印输出。为了完整起见,我们还为实例添加了一个值。
该示例创建了一个新实例。然后将该值转换为字符串 using __repr__(通过使用该repr()函数。接下来将该字符串值传递给eval()它将评估字符串并返回结果。结果将是同一类的新实例并存储在 中second_instance。我们还打印出id()以可视化我们确实有两个不同的实例。最后我们证明first_instance == second_instance确实是True:
class MyClass:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return isinstance(self, MyClass) and self.value == other.value
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.value)
first_instance = MyClass(123)
print('First instance: repr=%r, id=%d' % (first_instance, id(first_instance)))
stringified = repr(first_instance)
print('Stringified: %r' % stringified)
second_instance = eval(stringified) # !!! DANGEROUS (see below) !!!
print('Second instance: repr=%r, id=%d' % (second_instance, id(second_instance)))
print('First == Second: %r' % (first_instance == second_instance))
Run Code Online (Sandbox Code Playgroud)
如果绝对一切都在您的控制之下,这是100%可以接受的!这意味着:eval()
eval()被调用的范围在你的控制之下牢记所有这些并保证项目 I/O 在未来的任何时候都不会以eval()调用结束几乎是不可能的。因此,我强烈建议在重要的生产代码中避免这种情况,因为它会打开令人讨厌的安全漏洞。
对于不在生产环境中运行的代码,这是绝对可以接受的。例如单元测试、个人实用程序脚本等,但应始终考虑风险。
eval()在调用它的 Python 进程内执行,具有相同的权限。示例:您从多个用户可以访问的数据库中读取一个值,然后您eval()就可以使用它了。在这种情况下,另一个用户可能会通过数据库注入代码,并且该代码将以您的用户身份运行!eval()时,值来自外部来源开辟了代码注入的可能性。repr()会返回有效的 Python 表达式。这只是文档的建议。因此,对evalwith的调用__repr__容易出现运行时错误。eval()需要“知道”这个类MyClass(它必须被导入)。它只查找名称。因此,如果纯属偶然的情况下,作用域中存在相同的名称,但指向另一个对象,您将无意中调用其他东西,并可能遇到奇怪的错误。当然,这是一个边缘情况。使用许多可用的序列化选项之一。最流行、最简单的方法是将对象与 JSON 字符串相互转换。上面的例子可以像这样安全:
import json
class MyClass:
@staticmethod
def from_json(document):
data = json.loads(document)
instance = MyClass(data['value'])
return instance
def __init__(self, value):
self.value = value
def __eq__(self, other):
return isinstance(self, MyClass) and self.value == other.value
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.value)
def to_json(self):
data = {
'value': self.value
}
return json.dumps(data)
first_instance = MyClass(123)
print('First instance: repr=%r, id=%d' % (first_instance, id(first_instance)))
stringified = first_instance.to_json()
print('Stringified: %r' % stringified)
second_instance = MyClass.from_json(stringified)
print('Second instance: repr=%r, id=%d' % (second_instance, id(second_instance)))
print('First == Second: %r' % (first_instance == second_instance))
Run Code Online (Sandbox Code Playgroud)
这只是稍微困难一点,但更安全。
相同的方法可以与其他序列化方法一起使用。流行的格式有:
对于那些谁正在寻找覆盖转换内置命令,例如int(obj),float(obj)和str(obj),看到在Python超载INT() 。您需要在对象上实现__int__、__float__或__str__。
正如 Anand 在评论中指出的,您正在寻找的是对象序列化和反序列化。实现此目的的一种方法是通过 pickle(或 cPickle)模块:
>>> import pickle
>>> class Example():
... def __init__(self, x):
... self.x = x
...
>>> a = Example('foo')
>>> astr = pickle.dumps(a) # (i__main__\nExample\np0\n(dp1\nS'x'\np2\nS'foo'\np3\nsb.
>>> b = pickle.loads(astr)
>>> b
<__main__.Example instance at 0x101c89ea8>
>>> b.x
'foo'
Run Code Online (Sandbox Code Playgroud)
但请注意,使用 pickle 模块的一个问题是处理实现版本。正如 Python 文档中所建议的,如果您希望未腌制的实例自动处理实现版本控制,您可能需要添加版本实例属性并添加自定义 __setstate__ 实现:https: //docs.python.org/2/library/pickle .html#对象。设置状态。否则,无论对对象本身进行的代码更改如何,序列化时对象的版本将与反序列化时获得的版本完全相同。
| 归档时间: |
|
| 查看次数: |
10113 次 |
| 最近记录: |