你所不知道的python--3

Interesting in python(3)


think twice before coding

再怎么小心也不为过

小心使用return

@python 3.6.7

def func():
    if 1 == 2:
        return True


return_result = func()
print(return_result)  # None

if return_result is not False:
    print(True)  # True

  上面代码很好理解,1不等于2于是返回空即为None。python任何函数都有返回值,没有在语句分支中定义或者本来就不打算return,就返回None。这很大程度上增强了语言的灵活性并且减少了代码量,但在注重规范表达时应该要在明确返回False时使用return,毕竟None is not False

@python 3.6.7

def func():
    try:
        return 'hello first'
    finally:
        return 'hello finally'


print(func())  # hello finally

  try...finally语句中执行return,break,continue后,都会执行finally语句,而函数的返回值是由最后执行的return决定的,所以最后return的是hello finally

认真对待嵌套

@python 3.6.7

func_list = []
normal_list = []

for i in range(11):
    def func():
        return i
    func_list.append(func)  # 存储函数,未调用函数
    normal_list.append(func())  # 存储函数返回值,调用函数

func_list_result = [func() for func in func_list]  # 此时再调用

print(normal_list)
print(func_list_result)
# result
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

  当在循环内部定义一个函数时,如果函数使用了循环变量,比如上面中的i,那么所有的函数都会使用最后分配给变量的值即上面中的10来进行计算。func_list就是这样,而normal_list中的函数在循环中正常执行返回变量i的值。
  那么如何推迟函数执行而达到和normal_list一样的效果呢?

@python 3.6.7

func_list = []

for i in range(11):
    def func(x=i):
        return x
    func_list.append(func)  # 存储函数,未调用函数

func_list_result = [func() for func in func_list]  # 此时再调用

print(func_list_result)
# result
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

  将循环变量作为参数传给函数就行了,x也可以换成i,命名无所谓,但是为了表意清晰还是重命名比较好。此时函数会在内部重新定义一个局部变量,每循环一次都会存储循环变量i

boolean and int

@python 3.6.7

some_list = [1, 1.0, 0, True, False, [], "string"]
for item in some_list:
    if isinstance(item, int):
        print(item)
# result
# 1
# 0
# True
# False

  从上面我们可以看出,其实booleanint类型的子类。因此True的整数值是1,而False的整数值是0

@python 3.6.7

>>> True == 1 == 1.0
True
>>> False == 0 == 0.0
True
>>> # but
...
>>> True is 1
False
>>> True = False  # SyntaxError: can't assign to keyword

  所以当我们做出下面的神奇操作时,请小心:

@python 3.6.7

test_dict = {}stack
test_dict[True] = 'java'
test_dict[1] = 'js'
test_dict[1.0] = 'python'

print(test_dict[True])  
for key, value in test_dict.items():
    print(key, value)

# result
# python
# True python

  这是因为python字典以键来存储值,给相同的键赋值会覆盖之前键的值;而键的区分是通过计算hash值。

@python 3.6.7

print(hash(True), hash(1), hash(1.0))
# result
# 1 1 1

类的属性

@python 3.6.7

class Father:
    first_list = [0]
    second_list = [0]

    def __init__(self, x):
        self.first_list = self.first_list + [x]
        self.second_list += [x]


sub_one = Father(200)
print(sub_one.first_list)
print(sub_one.second_list)
# result
# [0, 200]
# [0, 200]

sub_two = Father(300)
print(sub_two.first_list)
print(sub_two.second_list)
# result
# [0, 300]
# [0, 200, 300]

  之所以会出现上面的原因是因为python类变量和实例变量是通过字典来处理的。如果在当前类的字典中找不到就去它的父类去找,而+=运算符会原地修改可变对象,不会重新创建新的对象,因此(类的创建省略,和上面一样):

@python 3.6.7

print(sub_one.first_list is sub_two.first_list)  # False
print(sub_one.second_list is sub_two.second_list)  # True

# and you will see
print(sub_one.second_list)  # [0, 200, 300]
print(Father.second_list)  # [0, 200, 300]

对yield不要太随心所欲

@python 3.6.7

iterable = ['a', 'b']


def do_something(no_use):
    return 'do_something'


iter1 = [(yield x) for x in iterable]
print(list(iter1))
# ['a', 'b']

iter2 = ((yield x) for x in iterable)
print(list(iter2))
# ['a', None, 'b', None]

iter3 = (do_something((yield x)) for x in iterable)
print(list(iter3))
# ['a', 'do_something', 'b', 'do_something']

iter4 = [do_something((yield x)) for x in iterable]
print(list(iter4))
# ['a', 'b']

  this is a bug!
  对此stackoverflow中给出了完善的答复,值得一提的是这个bug在python 3.8中已经修复,直接报语法错误_。但对于我们来说或许真正应该学会的是如何正确的理解和使用快捷舒适的python。下面是对yield的官方引用:

The yield expression is only used when defining a generator function and thus can only be used in the body of a function definition.

可变和不可变

@python 3.6.7

>>> test_tuple = ([1, 2], [2, 3])
>>> test_tuple[1].append(1000)
>>> test_tuple
([1, 2], [2, 3, 1000])
>>> test_tuple[1] += [2000]
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> test_tuple  # go on to check value
([1, 2], [2, 3, 1000, 2000])

  不可变序列,不可变序列的对象一旦创建就不能再改变. (如果对象包含对其他对象的引用,则这些其他对象可能是可变的并且可能会被修改; 但是,由不可变对象直接引用的对象集合不能更改.)

  首先来我们重温一下+=运算符,对于可变对象例如:list会直接在原对象上进行修改;而对于不可变对象例如:tuplea += b等价于a = a + b,会产生新的对象然后赋值给原来的变量引用即a
  所以+=操作符会在原地修改列表,但元素赋值操作=对于元组并不工作,因此会抛出异常,但此时元素的值已经改变了。因此我们可以这样认为,实际上+=是两个操作:

@python 3.6.7

test_tuple[1] += [2000]
# means
test_tuple[1].extend([2000])  # it works, change list
test_tuple[1] = test_tuple[1]  # error

一些有趣的赋值

@python 3.6.7

>>> a, b = a[b] = {}, 2
>>> a
{2: ({...}, 2)}
>>> b
2

  上面赋值语句我们可以这样来看,在右边最后一个等号前面都称为目标列表,即目标列表是a, ba[b];而表达式只能有一个即{}, 2。表达式计算结束后,会将其值从左到右分配给目标列表。
  因此a, b会先分别赋值为{}2;接着再将{}, 2赋值给a[b]a[2]。那么现在就是将字典中键为2的值设置为元组{}, 2,此时会造成循环引用,因为{}和之前的a都引用了相同的对象,所以结果是{2: ({...}, 2)}。(输出中的{...}指与a引用了相同的对象)

@python 3.6.7

# same as this
>>> a, b = {}, 2
>>> a[b] = a, b
>>> a
{2: ({...}, 2)}
>>> a[b][0] is a  # same object 
True
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,932评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,554评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,894评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,442评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,347评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,899评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,325评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,980评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,196评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,163评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,085评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,826评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,389评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,501评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,753评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,171评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,616评论 2 339