print('Hello World!') 在 python 的代码中不使用 'e' 也不使用 'p'
print('Hello World!') not using 'e' nor 'p' in the code with python
这个问题可能看起来很傻。
这是一个简单无用的任务,但我相信这是学习东西的好方法(我在做这种技巧时确实学到了很多东西)。
所以,想法在标题中:
不允许 'e' => 不允许 eval() 或 exec()
不允许 'p' => 不允许 print() 或 import
我尝试的是从以下位置获取打印功能:
dir(__builtins__)[133]
但它是作为字符串返回的,我找不到将其作为可调用函数获取的方法。
由于内置字典的顺序是随机的,这不是一件很有用的事情,除非你像调用 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>)]
糟糕,我用 e
来表示 items
,对吧?罚款:
>>> [__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
模块呢?我们可以使用相同的backslash/etc。很容易获得名称 'inspect'
的技巧,但是(除非我们可以假设它已经导入到 sys.modules
——并且 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
在语句中创建命名函数而不是在表达式中创建匿名函数是一种反模式,但是整个 post 就是一堆反模式模式。我在这里这样做是为了避免需要 def
和 return
,它们都有 e
(正如 Elliot Frisch 所指出的)。 (很难注意到您键入的所有 e
;甚至 Gadsby 中也有三个意外的 e,而且它以没有 e 的小说而闻名……)
我敢肯定有人希望我会展示如何通过使用编译的字节码文字来解决这个问题,对吗?
不幸的是,只有两种方法可以 运行 一个代码对象:要么将它包装在一个函数对象中——这需要获得 FunctionType
,这需要一个 import
或者给 type
的电话——或者你 exec
或 eval
它——已经结束了。
此外,在 Python 3 中,您要做的就是将常量 "print"
和 "Hello, World"
填入 co_names
和 co_consts
,以及那么它只是一个 LOAD_NAME
、LOAD_CONST
、CALL_FUNCTION
、RETURN_VALUE
(巧合的是,它恰好以 e
: b'e\x00d\x00\x83\x01S\x00'
开头)。
在Python 2中,另一方面,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
。)
这个问题可能看起来很傻。 这是一个简单无用的任务,但我相信这是学习东西的好方法(我在做这种技巧时确实学到了很多东西)。
所以,想法在标题中: 不允许 'e' => 不允许 eval() 或 exec() 不允许 'p' => 不允许 print() 或 import
我尝试的是从以下位置获取打印功能:
dir(__builtins__)[133]
但它是作为字符串返回的,我找不到将其作为可调用函数获取的方法。
由于内置字典的顺序是随机的,这不是一件很有用的事情,除非你像调用 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>)]
糟糕,我用 e
来表示 items
,对吧?罚款:
>>> [__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
模块呢?我们可以使用相同的backslash/etc。很容易获得名称 'inspect'
的技巧,但是(除非我们可以假设它已经导入到 sys.modules
——并且 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
在语句中创建命名函数而不是在表达式中创建匿名函数是一种反模式,但是整个 post 就是一堆反模式模式。我在这里这样做是为了避免需要 def
和 return
,它们都有 e
(正如 Elliot Frisch 所指出的)。 (很难注意到您键入的所有 e
;甚至 Gadsby 中也有三个意外的 e,而且它以没有 e 的小说而闻名……)
我敢肯定有人希望我会展示如何通过使用编译的字节码文字来解决这个问题,对吗?
不幸的是,只有两种方法可以 运行 一个代码对象:要么将它包装在一个函数对象中——这需要获得 FunctionType
,这需要一个 import
或者给 type
的电话——或者你 exec
或 eval
它——已经结束了。
此外,在 Python 3 中,您要做的就是将常量 "print"
和 "Hello, World"
填入 co_names
和 co_consts
,以及那么它只是一个 LOAD_NAME
、LOAD_CONST
、CALL_FUNCTION
、RETURN_VALUE
(巧合的是,它恰好以 e
: b'e\x00d\x00\x83\x01S\x00'
开头)。
在Python 2中,另一方面,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
。)