Duck Typing and Asking Forgiveness, Not Permission (EAFP)

  • Pythonic

You are following conventions and coding styles of the Python language in order to write clean and readable code

Duck Typing

  • 如果一个object叫声像鸭子,走路姿势像鸭子,那么它就是鸭子。
  • 我们不关心操作的实例化对象本身是什么类型(class),只关心它们是否可以正确的完成我们希望完成的工作,即这个对象的行为(method)是否可以完成我们希望的工作,如果可以,那么它就是我们需要的类型。
class Duck:

    def quack(self):
        print('Quack, quack')

    def fly(self):
        print('Flap, Flap!')


class Person:

    def quack(self):
        print("I'm Quacking Like a Duck!")

    def fly(self):
        print("I'm Flapping my Arms!")

Not Duck-Typed (Non-Pythonic)

def quack_and_fly(thing):
    pass
    # Not Duck-Typed (Non-Pythonic)
    if isinstance(thing, Duck):
        thing.quack()
        thing.fly()
    else:
        print('This has to be a Duck!')
d = Duck()
p = Person()

quack_and_fly(d)
quack_and_fly(p)
Quack, quack
Flap, Flap!
This has to be a Duck!

Duck typing (Pythonic)

def quack_and_fly(thing):
        thing.quack()
        thing.fly()
d = Duck()
p = Person()

quack_and_fly(d)
quack_and_fly(p)
Quack, quack
Flap, Flap!
I'm Quacking Like a Duck!
I'm Flapping my Arms!

但是,这样是不是太危险了?OK,我们可以不去关心我们操作的对象的类型,但是我们至少需要检查一下这些传入的对象有没有这些method吧?下面我们来讨论这个问题。

EAFP

Easier to Ask Forgiveness than Permission

Look before you leap

传统的方式,实现这种检查,需要先用hasattr检查该类的实例化对象是否存在相应的属性,然后检查该属性是否可以被调用,这样看上去十分的cumbersome(累赘和复杂)。

采用这种方式,我们每次都需要在执行之前先进行询问permission

 #  Non-Pythonic
def quack_and_fly(thing):
    # LBYL (Non-Pythonic)
    if hasattr(thing, 'quack'):
        if callable(thing.quack):
            thing.quack()

    if hasattr(thing, 'fly'):
        if callable(thing.fly):
            thing.fly()
        print()
d = Duck()
p = Person()

quack_and_fly(d)
quack_and_fly(p)
        
Quack, quack
Flap, Flap!

I'm Quacking Like a Duck!
I'm Flapping my Arms!

EAFP 示例

Let us try do something, and if it doesn’t work then we’ll handle it.

  • case 1:‘Duck’ object has no attribute ‘bark’

我们不需要进行类型检查,也不需要进行属性和调用检查。直接进行执行,当遇到问题时,直接可以抛出异常

# Pythonic
def quack_and_fly(thing):
    try:
        thing.quack()
        thing.fly()
        thing.bark()
    except AttributeError as e:
        print(e)
    print()
d = Duck()
p = Person()

quack_and_fly(d)
quack_and_fly(p)
Quack, quack
Flap, Flap!
'Duck' object has no attribute 'bark'

I'm Quacking Like a Duck!
I'm Flapping my Arms!
'Person' object has no attribute 'bark'
  • case 2:Missing’job’ key
#  person = {"name": "jess","age":"22","job":"programmar"}
person = {"name": "jess","age":"22"}
#  Non-Pythonic
if "name" in person and "age" in person and "job" in person:
    print("i am {name}.I am {age} years old and i am a {job}".format(**person))
else:
    print("missing some keys")
missing some keys
# Pythonic
try:
     print("i am {name}.I am {age} years old and i am a {job}".format(**person))
except KeyError as e:
    print("Missing{} key".format(e))
Missing'job' key
  • case 3:that index does not exist
my_list = [1,2,3,4,5]
#  Non-Pythonic
if len(my_list) >=6:
    print(my_list[5])
else:
    print("that index does not exist")
that index does not exist
# Pythonic
try:
    print(my_list[5])
except IndexError:
    print("that index does not exist")
that index does not exist
  • case 4:with open a file

我们先检查文件是否可以访问,然后准备打开文件,但是因为是race condition的情况,即在很短的时间内,文件可能被占用,而当我们真的去打开文件的时候,可能会失败,而之前我们已经检查过可以成功了,所以这种情况下,我们就不会捕捉到这个错误了。

import os
#  Non-Pythonic
# race condition 
my_file = "name.csv"
if os.access(my_file, os.R_OK):
    with open(my_file) as f:
        print(f.readline())
else:
    print("file can not be accessed ")
first_name,last_name,email

而采用 try except的方式,我们先去尝试做,如果成功,则直接读取文件显示,而如果失败则抛出异常。

# Pythonic
try:
    f = open(my_file)
except IOError as e:
    print("file can not be accessed")
else:
    with f:
        print(f.readline())
first_name,last_name,email

引用

本文主要参考下列视频内容,翻译并亲测代码后形成此文,感谢视频作者的无私奉献!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值