逆向之旅:七个让Python编程更糟糕的小技

开发 前端
文章带大家进入Python编程的奇特角落,探索那些完全出乎意料甚至无厘头的编程事实。在这里,你可以窥见如何在一行内完成复杂的函数,或者是如何完全无视掉代码中的assert语句。

文章带大家进入Python编程的奇特角落,探索那些完全出乎意料甚至无厘头的编程事实。在这里,你可以窥见如何在一行内完成复杂的函数,或者是如何完全无视掉代码中的assert语句。

如果你想在Python编程方面变得更糟糕,那么,这篇文章就是为你量身定制的。

(1) _.__.___.____._____ 也能行

class Test:
    def __getattr__(self, key):
        return Test()

在一个类中,当1用于访问someattribute属性2时调用magic方法someattributes属性没有显式定义__getattribute__object.someattribute。

class Test:
    def __getattr__(self, key):
        return Test()


_ = Test()

print(_)
print(_.__)
print(_.__.___)
print(_.__.___.____)
print(_.__.___.____._____)

# <__main__.Test object at 0x1098834d0>
# <__main__.Test object at 0x109883500>
# <__main__.Test object at 0x1098835c0>
# <__main__.Test object at 0x1098835c0>
# <__main__.Test object at 0x109883500>
  • _就是一个测试类对象
  • _.__调用,返回另一个 Test 对象__getattr__
  • _.__.___又一次调用,返回另一个Test 对象__getattr__
  • _.__.___.____再一次调用,返回另一个Test 对象__getattr__
  • _.__.___.____._____继续调用,返回另一个Test 对象__getattr__
  • 这就是可能的_.__.___.____._____

(2) 利用exec()在一行中写代码

如果你曾经想要学的是如何在一行代码中写出任何 Python 函数,那么这点就适合你。假设有一个多行函数,但是并不知道如何才能合法地把它压缩成一行代码

def hi():
    print('apple')
    print('orange')

为了便于理解,这里有一个简明易懂的例子。

exec("def hi():\n. print('apple')\n  print('orange')")

exec()会将字符串作为Python代码来执行 因此,如果将函数编成字符串格式并把提供给exec,就成功地用python的一行代码来写出这个函数了

(3) Dog()()()()可以是有效代码

class Dog:
    pass


dog = Dog()
print(dog())  # error

目前得到了一个错误,这是因为默认情况下,是不能将一个对象像一个函数一样去调用的。

class Dog:
    def __call__(self):
        return 'apple pie'


dog = Dog()
print(dog())  # apple pie

定义魔术方法__call__可以决定对象的调用行为,就像对函数进行调用一样。

class Dog:
    def __call__(self):
        return Dog()


dog = Dog()
print(dog())  # <class '__main__.Dog'>

在这,让__call__返回一个新的 Dog 对象。

print(Dog()()()()())

由于每次都得到一个新的 Dog 对象,无论何时对Dog对象进行调用,都可以无限地调用下去。

(4) 多个负号的问题

x = -1--2---3----4-----5

这是有效的 Python 代码:

  • 1-2可以被解读为 1 减 2
  • -1则被看成负数(不是减法的负号)
  • --1是负负,就等于 1
  • ---1是负负负的,又变成了 -1
  • 这种情况就会一直持续下去

-1--2---3----4-----5:因此,这是合法的 Python 代码-1-(-2)-(--3)-(---4)-(----5)

(5)如何限制使用print()

print = None

print('hello world')

# TypeError: 'NoneType' object is not callable

在这,将print = None,将None赋值给了print。这覆盖了非常熟悉的常用函数,因此我们现在无法使用print()。

print = None

__builtins__.print('hello')  # hello

但可以用__builtins__.print来访问原来的print()功能!

print = None
__builtins__ = None

如果让__builtins__设置为None。现在没有人能再使用 print() 了。

(6)让全局变量都消失

a = 4
b = 5
c = 6

keys = list(globals().keys())
for key in keys:
    del globals()[key]
del globals()['keys']
del globals()['key']

print(globals())  # {}

print(a)  # 'a' 没有定义
  • globals()会返回含有所有全局变量的字典
  • 可以删掉所有在globals()中的键值对
  • 删完后,globals()变成了空的
  • 这意味着没有剩余的全局变量,并且之前定义的所有全局变量都一去不复返了

(7)可无视assert语句

你是不是经常assert代码语句困扰?别担心,因为有一种方法能让你完全无视掉assert语句。

# hello.py
assert 1 == 2

如果用python hello.py来运行它,由于 assert 语句,会收到一个 AssertionError。

# hello.py
assert 1 == 2
  • 也可以选择用python -O hello.py来运行它
  • -O标志让 Python 忽略所有的assert语句
  • 现在,可以让你的代码忽略所有 assert 语句,无论它们会捕获何种错误!毕竟,谁在乎呢?

结论

文章带大家进入Python编程的奇特角落,探索那些完全出乎意料甚至无厘头的编程事实。在这里,你可以窥见如何在一行内完成复杂的函数,或者是如何完全无视掉代码中的assert语句。

如果你对编程充满好奇或者想成为一个更糟糕的程序员,那么这篇文章将为你揭开一个被藏在细节里的惊人世界。


责任编辑:华轩 来源: 哈希编程
相关推荐

2023-10-04 17:41:39

编程习惯代码

2015-06-11 13:34:54

编程编程阶段

2023-04-07 17:44:43

2013-07-10 11:33:17

AndroidiOS隐私

2023-01-05 14:58:54

2021-08-17 10:08:44

HTML网站网络

2023-06-02 15:53:38

工具Python开发

2023-03-23 15:18:03

JavaScrip代码实践

2011-07-04 08:51:27

编程

2021-06-28 11:46:31

GitLinux

2021-09-22 12:45:47

Python数据分析

2011-02-22 10:23:34

2021-08-02 08:21:53

Python编程语言开发

2022-05-23 11:13:02

Python工具

2023-08-30 07:25:20

Windows协作式DC

2023-10-08 09:52:55

2016-09-28 09:58:59

网络安全应用安全

2013-05-29 10:57:34

数据中心网络数据中心数据中心网络设置

2022-10-08 13:13:14

Python程序性能

2020-05-25 15:50:59

物联网物联网设备IOT
点赞
收藏

51CTO技术栈公众号