python 2和3之間的一個變化是後者代表x.__round__([n])
操作round(x, n)
。在python 2中,對於我的類實現__round__
和__float__
,當我調用round(x)
時,調用了x.__float__
。__float__和__round__在python 2和3中
我怎麼知道round(x)
(而不是float(x)
)被調用來重新路由在Python 2適當的調用,並獲得類似python 3的行爲。
感謝
更新:我想出了一個醜陋的黑客。我確信:
- 它可以改進。
- 它不會總是工作。
- ndigits參數不在python 2中處理。
- 它不應該用於生產。
但無論如何建立它很有趣。感謝所有的澄清。
import dis
import sys
import inspect
import functools
#'CALL_FUNCTION', 'CALL_FUNCTION_VAR', 'CALL_FUNCTION_KW', 'CALL_FUNCTION_VAR_KW'
HUNGRY = (131, 140, 141, 142)
if sys.version < '3':
def is_round(frame):
"""Disassemble a code object."""
co = frame.f_code
lasti = frame.f_lasti
code = co.co_code
i, n = 0, len(code)
extended_arg = 0
free = None
codes = list()
while i < n:
c = code[i]
op = ord(c)
tmp = [op, ]
i += 1
if op >= dis.HAVE_ARGUMENT:
oparg = ord(code[i]) + ord(code[i + 1]) * 256 + extended_arg
extended_arg = 0
i += 2
if op == dis.EXTENDED_ARG:
extended_arg = oparg * long(65536)
tmp.append(oparg)
if op in dis.hasconst:
tmp.append(repr(co.co_consts[oparg]))
elif op in dis.hasname:
tmp.append(co.co_names[oparg])
elif op in dis.hasjrel:
tmp.append(repr(i + oparg)),
elif op in dis.haslocal:
tmp.append(co.co_varnames[oparg])
elif op in dis.hascompare:
tmp.append(dis.cmp_op[oparg])
elif op in dis.hasfree:
if free is None:
free = co.co_cellvars + co.co_freevars
tmp.append(free[oparg])
else:
tmp.append(None)
else:
tmp.append(None)
tmp.append(None)
codes.append(tmp)
if i > lasti:
break
pending = 1
for (opcode, arguments, param) in reversed(codes):
pending -= 1
if opcode in HUNGRY:
pending += arguments + 1
if not pending:
seen = dict(frame.f_builtins)
seen.update(frame.f_globals)
seen.update(frame.f_locals)
while param in seen:
param = seen[param]
return param == round
def round_check(func):
@functools.wraps(func)
def wrapped(self):
if is_round(inspect.currentframe().f_back):
return self.__round__()
return func(self)
return wrapped
else:
def round_check(func):
return func
class X():
@round_check
def __float__(self):
return 1.0
def __round__(self, ndigits=0):
return 2.0
x = X()
r = round
f = float
assert round(x) == 2.0
assert float(x) == 1.0
assert r(x) == 2.0
assert f(x) == 1.0
assert round(float(x)) == 1.0
assert float(round(x)) == 2.0
我也看看它是否可用__future__第一!重新定義問題的關鍵是我正在建立一個圖書館。所以我不能控制如何使用圓。我在跳躍,有可能反思堆棧,並找出它是否被round() – Hernan 2012-03-17 20:21:05
調用哦,不要那樣做。這將是可怕的脆弱和越野車。你想在'round'中執行不同的行爲是什麼?也就是說,你認爲'round(x)'的價值是什麼? – katrielalex 2012-03-17 20:28:37
請記住,在Python 2.x中'round'總是返回一個浮點數 - 所以你不希望你的類違反合同! – katrielalex 2012-03-17 20:29:08