文章目录
- 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
引用
本文主要参考下列视频内容,翻译并亲测代码后形成此文,感谢视频作者的无私奉献!