python里i每次进入if自加_如何让self进入Python方法而不显式地接受i

本文介绍了一种使用Python元类的方法,通过`add_self`装饰器,将'self'参数自动插入到方法定义中,简化了代码并保持了可移植性。作者通过实例展示了如何修改函数的字节码来实现这一功能,并在`Test`类中进行了演示。
摘要由CSDN通过智能技术生成

我对这个问题的回答很愚蠢,但我才刚刚开始。这里有一个更好的方法。这只是很少的测试,但它有利于演示正确的方法做这件事,这是不适当的。它当然可以在2.6.5上运行。我还没有测试过其他版本,但是没有任何操作码被硬编码到里面,所以它应该和大多数其他2.x代码一样便携。在

add_self可以作为decorator应用,但这会破坏目的(为什么不只键入'self'从我的另一个答案改编元类来应用这个函数是很容易的。在import opcode

import types

def instructions(code):

"""Iterates over a code string yielding integer [op, arg] pairs

If the opcode does not take an argument, just put None in the second part

"""

code = map(ord, code)

i, L = 0, len(code)

extended_arg = 0

while i < L:

op = code[i]

i+= 1

if op < opcode.HAVE_ARGUMENT:

yield [op, None]

continue

oparg = code[i] + (code[i+1] << 8) + extended_arg

extended_arg = 0

i += 2

if op == opcode.EXTENDED_ARG:

extended_arg = oparg << 16

continue

yield [op, oparg]

def write_instruction(inst):

"""Takes an integer [op, arg] pair and returns a list of character bytecodes"""

op, oparg = inst

if oparg is None:

return [chr(op)]

elif oparg <= 65536L:

return [chr(op), chr(oparg & 255), chr((oparg >> 8) & 255)]

elif oparg <= 4294967296L:

# The argument is large enough to need 4 bytes and the EXTENDED_ARG opcode

return [chr(opcode.EXTENDED_ARG),

chr((oparg >> 16) & 255),

chr((oparg >> 24) & 255),

chr(op),

chr(oparg & 255),

chr((oparg >> 8) & 255)]

else:

raise ValueError("Invalid oparg: {0} is too large".format(oparg))

def add_self(f):

"""Add self to a method

Creates a new function by prepending the name 'self' to co_varnames, and

incrementing co_argcount and co_nlocals. Increase the index of all other locals

by 1 to compensate. Also removes 'self' from co_names and decrease the index of

all names that occur after it by 1. Finally, replace all occurrences of

`LOAD_GLOBAL i,j` that make reference to the old 'self' with 'LOAD_FAST 0,0'.

Essentially, just create a code object that is exactly the same but has one more

argument.

"""

code_obj = f.func_code

try:

self_index = code_obj.co_names.index('self')

except ValueError:

raise NotImplementedError("self is not a global")

# The arguments are just the first co_argcount co_varnames

varnames = ('self', ) + code_obj.co_varnames

names = tuple(name for name in code_obj.co_names if name != 'self')

code = []

for inst in instructions(code_obj.co_code):

op = inst[0]

if op in opcode.haslocal:

# The index is now one greater because we added 'self' at the head of

# the tuple

inst[1] += 1

elif op in opcode.hasname:

arg = inst[1]

if arg == self_index:

# This refers to the old global 'self'

if op == opcode.opmap['LOAD_GLOBAL']:

inst[0] = opcode.opmap['LOAD_FAST']

inst[1] = 0

else:

# If `self` is used as an attribute, real global, module

# name, module attribute, or gets looked at funny, bail out.

raise NotImplementedError("Abnormal use of self")

elif arg > self_index:

# This rewrites the index to account for the old global 'self'

# having been removed.

inst[1] -= 1

code += write_instruction(inst)

code = ''.join(code)

# type help(types.CodeType) at the interpreter prompt for this one

new_code_obj = types.CodeType(code_obj.co_argcount + 1,

code_obj.co_nlocals + 1,

code_obj.co_stacksize,

code_obj.co_flags,

code,

code_obj.co_consts,

names,

varnames,

'',

code_obj.co_name,

code_obj.co_firstlineno,

code_obj.co_lnotab,

code_obj.co_freevars,

code_obj.co_cellvars)

# help(types.FunctionType)

return types.FunctionType(new_code_obj, f.func_globals)

class Test(object):

msg = 'Foo'

@add_self

def show(msg):

print self.msg + msg

t = Test()

t.show('Bar')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值