内容简介:什么是优雅的代码,今天大邓与你一起学习优雅的python代码。本文内容根据PyCon2018(克利夫兰)其实我们平常使用的列表、字符串等数据类型的一些方法就用到了莫属方法,比如这个字符串拼接操作,在字符串类的定义中使用了
什么是优雅的代码,今天大邓与你一起学习优雅的 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__()
, 当迭代器中没有更多的元素可供迭代,此时raiseStopIteration
,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)
运行结果
<__main__.IterableServer object at 0x1092ece10> ('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)
运行结果
<__main__.IterableServer2 object at 0x1092ecc88> {'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 '<User {}>'.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,'已授权,可以参加会议')
运行结果
<User smith> 已授权,可以参加会议 <User sam> 已授权,可以参加会议
但是涉及到检验某人是否有权限部分的代码不美观简洁,
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) <ipython-input-106-c6d3c0348559> in <module>() 17 18 for u in users: ---> 19 display_authenticated_user(u) <ipython-input-106-c6d3c0348559> 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
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
大型网站系统与Java中间件开发实践
曾宪杰 / 电子工业出版社 / 2014-4-24 / 65.00
本书围绕大型网站和支撑大型网站架构的 Java 中间件的实践展开介绍。从分布式系统的知识切入,让读者对分布式系统有基本的了解;然后介绍大型网站随着数据量、访问量增长而发生的架构变迁;接着讲述构建 Java 中间件的相关知识;之后的几章都是根据笔者的经验来介绍支撑大型网站架构的 Java 中间件系统的设计和实践。希望读者通过本书可以了解大型网站架构变迁过程中的较为通用的问题和解法,并了解构建支撑大型......一起来看看 《大型网站系统与Java中间件开发实践》 这本书的介绍吧!