这个问题可能看起来很愚蠢。这是一个简单而无用的任务,但我相信这是一个学习东西的好方法(我在做这类技巧时确实学到了很多东西)。
所以,idea在标题中: no 'e‘allowed => No eval() or exec() no 'p’allowed => No print() or import
我尝试的是从以下位置获取打印函数:
dir(__builtins__)[133]
但它是以字符串的形式返回的,我发现没有办法将其作为可调用的函数来获取。
发布于 2018-07-20 08:25:45
由于内建字典的顺序是随机的,所以这不是一件非常有用的事情,除非你像调用print
一样喜欢调用staticmethod
。
但是知道如何从那里进入你想要的下一步可能是值得的。
模块就是对象,就像任何其他对象一样。因此,您可以使用getattr
获取它们的属性。好吧,这违反了你的规则。但大多数对象-包括模块-将其属性存储在字典中。所以:
>>> dir(__builtins__)[133]
'staticmethod'
>>> __builtins__.__dict__[_]
<type 'staticmethod'>
有没有什么办法能让我们真的找到print
?好吧,也许不能保证,但很接近:
>>> [v for k, v in __builtins__.__dict__.items() if 'rint' in k]
[('print', <function print>)]
哦,我对那个items
用的是e
,对吧?很好:
>>> [__builtins__.__dict__[k] for k in __builtins__.__dict__ if 'rint' in k]
[<function print>)]
>>> [__builtins__.__dict__[k] for k in __builtins__.__dict__ if 'rint' in k][0]('zzz')
zzz
但同时,您计划如何在没有e
的情况下构建字符串'Hello World!'
?有很多选择-\x
或\u
转义,或者像rot13
这样非常愚蠢的东西。所有这些选项都可以让您轻松地获得字符串'print'
。所以,我不明白为什么你一开始就想把print
从模块的名字中去掉。
>>> __builtins__.__dict__['\x70rint']
<function print>
正如John Anderson在评论中指出的那样,使用inspect
模块比使用__dict__
更好。首先,它适用于在其他地方存储属性的对象-甚至是使用自定义__dir__
和__getattr__
动态生成属性的对象。
>>> [v for k, v in inspect.getmembers(__builtins__) if k == 'print'][0]
<function print>
问题是,我们如何获得inspect
模块?我们可以使用相同的反斜杠/等技巧轻松地获得名称'inspect'
,但是(除非我们可以假设它已经导入到sys.modules
-and中,那么sys
也已经导入),我们需要import
或__import__
,或者使用importlib
或…它们都有一个p
。然后,为了获得getmembers
,我们需要查看inspect
模块的字典来按名称查找它。
但是,也许这样做一次比每次都做更好:
>>> i = __builtins__.__dict__['__im\x70ort__']
>>> ins = i('ins\x70\x65ct')
>>> gm = ins.__dict__['g\x65tm\x65mb\x65rs']
>>> builty = lambda nam: dict(gm(__builtins__))[nam]
>>> builty('\x70rint')
<function print>
>>> builty('\x65val')
<function eval>
当然,使用lambda
在语句中创建命名函数,而不是在表达式中创建匿名函数,这是一种反模式,但这整篇文章都是一堆反模式。我在这里这样做是为了避免对def
和return
的需要,它们都有e
s (正如Elliot Frisch所指出的那样)。(很难注意到您输入的所有e
;即使是Gadsby
我确信有人希望我能展示如何通过使用已编译的字节码文字来解决这个问题,对吧?
不幸的是,运行代码对象只有两种方法:要么将其包装在一个函数对象中-这需要获取FunctionType
,这需要一个import
或对type
-or you exec
或eval
it的调用-这些方法已经出来了。
另外,在Python3中,您所要做的就是将常量"print"
和"Hello, World"
塞进co_names
和co_consts
中,然后它只是一个LOAD_NAME
、LOAD_CONST
、CALL_FUNCTION
、RETURN_VALUE
(巧合的是,它恰好以e
:<代码>D53开头)。
另一方面,在Python2中,print
是一个语句,并且有一个特殊的PRINT_ITEM
字节码,所以它可能更有趣:
>>> ty = builty('typ\x65')
>>> gattr = builty('g\x65tattr')
>>> f = lambda: None
>>> c = gattr(f, 'func_cod\x65')
>>> ct = ty(c)
>>> cc = ct(0, 0, 1, 0x43, 'd\x00\x00\x04GS', ('H\x65llo World!',),
... (), (), '', 'h\x65llo', 0, '')
>>> xval = builty('\x65val')
>>> xval(cc)
Hello World!
'Hello World!'
(末尾额外加引号的输出是因为我太懒而不去挖掘None
,所以返回了"Hello World!"
。代码为LOAD_CONST 0; DUP_TOP; PRINT_ITEM; RETURN_VALUE
。)
https://stackoverflow.com/questions/51433423
复制相似问题