优雅地解决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)

运行结果

4

可迭代类

  • 为了创建可迭代的(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)

运行结果

<__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,  Davidgetattr(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 wrapperException: 抱歉,david先生您未注册会议,无权进入会场

精选文章

五分钟带你了解随机森林

聊天机器人:十行代码让你秒变撩妹达人

100G 文本分析语料资源(免费下载)

15个最好的数据科学领域Python库

使用Pandas更好的做数据科学

抓取8w技能交换公告信息

【视频讲解】Scrapy递归抓取简书用户信息

美团商家信息采集神器

大邓强力推荐-jupyter notebook使用小技巧

10分钟理解深度学习中的~卷积~

深度学习之 图解LSTM

PyTorch实战: 使用卷积神经网络对照片进行分类

Pytorch实战:使用RNN网络对姓名进行分类

数据清洗 常用正则表达式大全

PySimpleGUI: 开发自己第一个软件

深度特征合成:自动生成机器学习中的特征

Python 3.7中dataclass的终极指南(一)

Python 3.7中dataclass的终极指南(二)

[计算消费者的偏好]推荐系统与协同过滤、奇异值分解

机器学习: 识别图片中的数字

应用PCA降维加速模型训练

如何从文本中提取特征信息?

使用sklearn做自然语言处理-1

使用sklearn做自然语言处理-2

机器学习|八大步骤解决90%的NLP问题

Python圈中的符号计算库-Sympy

Python中处理日期时间库的使用方法

用chardect库解决网页乱码问题

(0)

相关推荐

  • 面试题-python 什么是迭代器?

    前言 python 里面有 3 大神器:迭代器,生成器,装饰器.在了解迭代器之前,需弄清楚2个概念: 1.什么是迭代 2.什么是可迭代对象 迭代 如果给定一个list或tuple,我们可以通过for循 ...

  • 【Python 第75课】可迭代对象和迭代器

    for 循环是我们在 Python 里非常常用的一个语法,但你有没有思考过 for 循环是怎样实现的? 如果你以前接触过 C++,应该会知道类似 for (int i = 0; i < 100; ...

  • 一文掌握 Python 迭代器的原理

    理解迭代器是每个严肃的 Python 使用者学习 Python 道路上的里程碑.本文将从零开始,一步一步带你认识 Python 中基于类的迭代器. 相较于其他编程语言,Python 的语法是优美而清晰 ...

  • 流畅的Python 1. Python数据模型(特殊方法 __func__())

    文章目录 1. `__getitem__().__len__()` 方法 2. 特殊方法 1. __getitem__().__len__() 方法 举一个扑克牌的例子 import collecti ...

  • Python迭代器

    迭代器是可以迭代的对象. 在本教程中,您将了解迭代器的工作原理,以及如何使用__iter__和__next__方法构建自己的迭代器. 迭代器在Python中无处不在. 它们优雅地实现在循环,推导,生成 ...

  • 普通人可照搬的优雅气质穿搭,日常通勤两不误,轻松解锁高级美

    法式风凭借着优雅.简约与精致而深受大众欢迎,只是许多时候,法国博主们的身高.长相与肤色与亚洲女性差别偏大,导致同样的衣服穿不出那股子慵懒女人味. 而这次为大家分享的博主Elborn由于是韩国人,无论是 ...

  • 见空调漏水原因与解决方法及日常保养大全

    问题:1.室内机安装不牢固造成移位:室内机固定挂板安装固定不牢固,时间长了发生移位,导致排水管引出一侧位置偏高,造成排水困难. 解决方法:重新固定室内机,把室内机固定挂板安装固定好,让机子里高外低. ...

  • 如何解决Python编码错误”一文

    你又没有遇到过,在写代码最后运行的时候,出现运行不了,在解析其他文件的时候出现报错,那么你是如何解决的呢?今天小编为大家带来一个技术性问题是怎么解决的过程.用python解析文件(文件中含有中文),并 ...

  • 小米教你如何优雅的解决表白问题

    表白数独解析 高端数独变形系列020 规则 1.将数字1-9填入盘内空白格,使每一行每一列每一宫数字不重复. 2.标记白点(顺)表示四格数字按顺时针方向逐渐增大,标记黑点(逆)表示四格数字按逆时针方向 ...

  • 袋鼠优雅的解决一道平平无奇的9选6箭头(高端数独变形系列148)

    箭头数独(九选六)数独解析 高端数独变形系列148 规则:1.将1-9中的6个数字填入盘内空白格,使每一行每一列每一宫数字不重复.2.圆圈数字等于其箭头线上数字之和. 空盘+9选6,初看时有点蒙,不过 ...

  • 爆改112m²大平层!解决祖孙三代日常起居难题

    有始也者,有未始有始也者,有未始有夫未始有始也者.--庄子<齐物论> 译文:如果时间有开端,那么就会有还没开端的时候也就会有连没有开端的时候都还没有的时候. 住宅概况 住宅类型:住宅居住成 ...

  • 代码设计优化,如何优雅的使用Python实现数据库操作

    在之前文章中介绍了如何使用Python操作Mysql.SQLite.Oracle等结构化数据库,使用方式大同小异.总结一下,Python操作结构化数据库的大致流程如下: 创建数据库连接对象. 创建游标 ...

  • 生发用什么方法?解决脱发从日常做起!

    头顶头发稀少是很影响人外在形象的一件事情,长时间的脱发,头皮受伤,使得头顶部位的头发非常脆弱,经常掉发,脱发就容易产生头顶头发稀少,乃至秃顶的现象.那么生发用什么方法呢? 专家指出,头发少通常有两种情 ...

  • 成功解决Python中出现的TypeError: object of type 'zip' has no len()

    成功解决Python中出现的TypeError: object of type 'zip' has no len() 不罗嗦,直接解决问题! 解决问题 TypeError: object of typ ...