python能解决日常问题_优雅地解决 Python 的日常问题

什么是优雅的代码,今天大邓与你一起学习优雅的 python 代码。本文内容根据PyCon2018(克利夫兰) Nina Zakharenko - Elegant Solutions For Everyday Python Problems - PyCon 2018 大会演讲视频整理而来。

python魔术方法-双下划线

其实我们平常使用的列表、字符串等数据类型的一些方法就用到了莫属方法,比如

a = 'edf'

b = 'ggg'

print(a+b)

这个字符串拼接操作,在字符串类的定义中使用了 __add__ 这个魔法。现在我们定义Money类来表示不同的货币,并能计算汇率。

class Money:

#这里我们以美元作为计价单位1,方便理解

current_rates = {'$':1,

'¥':6}

def __init__(self, symbol, amount):

self.symbol = symbol

self.amount = amount

def __str__(self):

#用来将实例化显示出来

return f'{self.symbol}{self.amount}'

def convert(self, other):

#将rmb转化为美元计价

new_amount = other.amount/self.current_rates[other.symbol]*self.current_rates[self.symbol]

return Money(self.symbol, new_amount)

dollar = Money('$', 5)rmb = Money('¥', 5)

print(dollar)

print(rmb)

print(rmb.convert(dollar))

运行结果

$5

¥5

¥5.0

现在我们想计算这个人持有的dollar和rmb一共值多少钱,这里就用到 加法__add__

class Money:

current_rates = {'$':1,

'¥':6}

def __init__(self, symbol, amount):

self.symbol = symbol

self.amount = amount

def __str__(self):

return f'{self.symbol}{self.amount}'

def convert(self, other):

#汇率换算

new_amount = other.amount/self.current_rates[other.symbol]*self.current_rates[self.symbol]

return Money(self.symbol, new_amount)

def __add__(self, other):

#将两种不同的货币进行总价值计算

new_amount = self.amount + self.convert(other).amount return Money(self.symbol, new_amount)

dollar = Money('$', 5)rmb = Money('¥', 5)

print(dollar)

print(rmb)

print(dollar+rmb)

print(rmb+dollar)

运行结果

$5

¥5

$5.833333333333333

¥35.0

此外还有 __getitem__ 、__len__ 等更多的魔术方法,比如

class SquareShape:

def __len__(self):

#返回正方向的边数

return 4

my_square = SquareShape()

len(my_square)

运行结果

可迭代类

为了创建可迭代的(iterable)数据类型,定义时需要用到 __iter__()

__iter__() 必须返回迭代器iterator

为了让数据是迭代器iterator,必须使用 __next__() , 当迭代器中没有更多的元素可供迭代,此时raise StopIteration ,iterator不再进行迭代。

比如我们在这里定义一个可迭代数据类型IterableServer

class IterableServer:

services = [{'protocol':'ftp', 'port':21},

{'protocol':'ssh', 'port':22},

{'protocol':'http', 'port':80}]

def __init__(self):

#初始化 服务器 索引位置为第一个

self.current_index = 0

def __iter__(self):

#没有此方法,IterableServer就不能for循环迭代

return self

def __next__(self):

while self.current_index < len(self.services):

service = self.services[self.current_index]

self.current_index+=1

return service['protocol'], service['port']

raise StopIteration

#这是咱们平常使用的for循环

servers = IterableServer()

print(servers)

for s in servers:

print(s)

运行结果

('ftp', 21)

('ssh', 22)

('http', 80)

< main .IterableServer object at 0x1092a5898>说明我们是迭代器对象,可以使用for循环,这个有点像列表。每次for循环,我们都要iter自己本身。所以比较消耗内存空间。

现在我们将IterableServer中的 iter 重新定义,使用yield,让IterableServer变成生成器,每次循环只迭代当前位置的元素,而不是将本身全部迭代。

class IterableServer2:

services = [{'protocol':'ftp', 'port':21},

{'protocol':'ssh', 'port':22},

{'protocol':'http', 'port':80}]

def __init__(self):

#初始化服务器索引位置为第一个

self.current_index = 0

def __iter__(self):

for service in self.services:

yield service

def __next__(self):

while self.current_index < len(self.services):

service = self.services[self.current_index]

self.current_index+=1

return service['protocol'], service['port']

raise StopIteration

#这是咱们平常使用的for循环

servers2 = IterableServer2()

print(servers2)

for s in servers2:

print(s)

运行结果

{'protocol': 'ftp', 'port': 21}

{'protocol': 'ssh', 'port': 22}

{'protocol': 'http', 'port': 80}

检验下运行速度(时间)

def s1():

servers = IterableServer()

for s in servers:

s def s2():

servers2 = IterableServer2()

for s in servers2:

s%timeit s1()

1.06 µs ± 48.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit s2()

996 ns ± 39.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

从上面的运行时间看,IterableServer2比IterableServer快,大家可以以此来理解同样的数据,使用列表与生成器的速度是不同的。

getattr(object, name, default)

举例这是我们正常的方法调用

class Dog:

sound = 'Bark'

def speak(self):

print(self.sound +'!',self.sound+'!')

my_dog = Dog()

my_dog.speak()

运行结果

Bark! Bark!

使用getattr可以让我们通过使用字符串去调用实例中的方法

speak_method = getattr(my_dog, 'speak')

speak_method()

运行结果

Bark! Bark!

现在可能觉得区别不大,好像没必要学getattr。但是假设定义的类中有很多种方法,在某种情况下我们需要输入一个命令的名字,并执行这个方法,就用到getattr

class Operations:

def say_hi(self, name):

print('hello, ', name)

def say_bye(self, name):

print('Goodbye, ', name)

def default(self, arg):

print('Operations不存在这个方法')

operations = Operations()

getattr(operations, 'say_hi', operations.default)('David')

运行结果

hello, David

getattr(operations, 'say_hiiii', operations.default)('David')

运行结果

Operations不存在这个方法

装饰器

装饰器可以用来让我们的代码更简洁美观,我们看一个例子。比如我们要举行一个会议,只让授权的人参加。

class User:

def __init__(self, name, is_authenticated=False):

self.name = name

self.is_authenticated = is_authenticated

def __str__(self):

return ''.format(self.name)

user1 = User('david')

user2 = User('smith', True)

user3 = User('sam', True)

users = [user1, user2, user3]

for u in users:

if u.is_authenticated == True:

print(u,'已授权,可以参加会议')

运行结果

已授权,可以参加会议

已授权,可以参加会议

但是涉及到检验某人是否有权限部分的代码不美观简洁,

def check(func):

def wrapper(user):

if not user.is_authenticated:

raise Exception('抱歉,{}先生您未注册会议,无权进入会场'.format(user.name))

return func(user)

return wrapper

@check

def display_authenticated_user(user):

print(user.name, '有权进入会场')

user1 = User('david')

user2 = User('smith', True)

user3 = User('sam', True)

users = [user2, user3, user1]

for u in users:

display_authenticated_user(u)

运行结果

smith 有权进入会场

sam 有权进入会场

---------------------------------------------------------------------------

Exception Traceback (most recent call last)

in ()

17

18 for u in users:

---> 19 display_authenticated_user(u)

in wrapper(user)

2 def wrapper(user):

3 if not user.is_authenticated:

----> 4 raise Exception('抱歉,{}先生您未注册会议,无权进入会场'.format(user.name))

5 return func(user)

6 return wrapper

Exception: 抱歉,david先生您未注册会议,无权进入会场

精选文章

深度学习之 图解LSTM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值