python 日志解决方案_日常Python问题的绝佳解决方案
python 日志解决方案
Python提供了一组独特的工具和语言功能,可帮助使您的代码更加优雅,可读性和直观性。 通过为正确的问题选择正确的工具,您的代码将更易于维护。 在本文中,我们将研究其中的三个工具:魔术方法,迭代器和生成器以及方法魔术。
魔术方法
__init__()
,当我们想初始化一个类的新实例时调用。
您可能已经看过其他常见的魔术方法,例如__str__
和__repr__
。 魔术方法无处不在,通过实现其中的一些魔术方法,我们可以极大地修改对象的行为,甚至使它的行为类似于内置的数据类型,例如数字,列表或字典。
让我们以这个Money
类为例:
class Money:
currency_rates = {
'$' : 1 ,
'€' : 0.88 ,
}
def __init__ ( self , symbol , amount ) :
self . symbol = symbol
self . amount = amount
def __repr__ ( self ) :
return '%s%.2f' % ( self . symbol , self . amount )
def convert ( self , other ) :
""" Convert other amount to our currency """
new_amount = (
other. amount / self . currency_rates [ other. symbol ]
* self . currency_rates [ self . symbol ] )
return Money ( self . symbol , new_amount )
该类为给定的符号和汇率定义货币汇率,指定一个初始化程序(也称为构造函数),并实现
__repr__ ,因此当我们打印该类时,我们看到一个很好的表示形式,例如$2.00
代表实例Money('$', 2.00)
,以及货币符号和金额。 最重要的是,它定义了一种方法,使您可以在具有不同汇率的不同货币之间进行转换。
假设我们使用Python外壳,以不同的货币定义了两种食品的成本,如下所示:
>>> soda_cost = Money ( '$' , 5.25 )
>>> soda_cost
$ 5.25
>>> pizza_cost = Money ( '€' , 7.99 )
>>> pizza_cost
€ 7.99
我们可以使用魔术方法来帮助此类的实例相互交互。 假设我们希望能够将此类的两个实例加在一起,即使它们使用不同的货币也是如此。 为了实现这个目标,我们可以在
Money类上实现__add__
魔术方法:
class Money:
# ... previously defined methods ...
def __add__ ( self , other ) :
""" Add 2 Money instances using '+' """
new_amount = self . amount + self . convert ( other ) . amount
return Money ( self . symbol , new_amount )
现在,我们可以以非常直观的方式使用此类:
>>> soda_cost = Money ( '$' , 5.25 )
>>> pizza_cost = Money ( '€' , 7.99 )
>>> soda_cost + pizza_cost
$ 14.33
>>> pizza_cost + soda_cost
€ 12.61
当我们将两个实例加在一起时,我们得到第一个定义的货币的结果。 所有转换都在后台无缝完成。 如果愿意,我们还可以实现
__sub__进行减法, __mul__
进行乘法等等。 阅读有关模拟数字类型的信息 ,或阅读本指南以了解其他方法 。
我们了解到__add__
映射到内置运算符+
。 其他魔术方法可以映射到[]
等符号。 例如,要通过索引或键(在字典的情况下)访问项目,请使用__getitem__
方法:
>>> d = { 'one' : 1 , 'two' : 2 }
>>> d [ 'two' ]
2
>>> d. __getitem__ ( 'two' )
2
一些魔术方法甚至映射到内置函数,例如
__len__() ,它映射到len()
。
class Alphabet:
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
def __len__ ( self ) :
return len ( self . letters )
>>> my_alphabet = Alphabet ( )
>>> len ( my_alphabet )
26
自定义迭代器
对于新手和老手而言,自定义迭代器是一个功能强大但令人困惑的话题。
许多内置类型(例如列表,集合和字典)已经实现了协议,允许它们在后台进行迭代。 这使我们可以轻松地遍历它们。
>>> for food in [ 'Pizza' , 'Fries' ] :
print ( food + '. Yum!' )
Pizza. Yum !
Fries. Yum !
我们如何迭代自己的自定义类? 首先,让我们澄清一些术语。
为了可迭代 ,一个类需要实现
__iter__()
__iter__()
方法需要返回一个迭代器- 要成为迭代器 ,一个类需要实现
__next__()
(或Python 2中的next()
),当没有更多要迭代的项时,它必须引发StopIteration
异常。
ew! 听起来很复杂,但是一旦您记住了这些基本概念,便可以在睡眠中进行迭代。
我们什么时候可以使用自定义迭代器? 假设有一个Server
实例在不同端口上运行不同服务(例如http
和ssh
的场景。 其中一些服务active
状态,而其他服务则inactive
。
class Server:
services = [
{ 'active' : False , 'protocol' : 'ftp' , 'port' : 21 } ,
{ 'active' : True , 'protocol' : 'ssh' , 'port' : 22 } ,
{ 'active' : True , 'protocol' : 'http' , 'port' : 80 } ,
]
当我们遍历
Server实例时,我们只想遍历active
服务。 让我们创建一个新类IterableServer
:
class IterableServer:
def __init__ ( self ) :
self . current_pos = 0
def __next__ ( self ) :
pass # TODO: Implement and remember to raise StopIteration
首先,我们将当前位置初始化为
0 。 然后,我们定义__next__()
方法,该方法将返回下一个项目。 我们还将确保在没有其他要返回的项目时提高StopIteration
。 到目前为止,一切都很好! 现在,让我们实现此__next__()
方法。
class IterableServer:
def __init__ ( self ) :
self . current_pos = 0 . # we initialize our current position to zero
def __iter__ ( self ) : # we can return self here, because __next__ is implemented
return self
def __next__ ( self ) :
while self . current_pos < len ( self . services ) :
service = self . services [ self . current_pos ]
self . current_pos + = 1
if service [ 'active' ] :
return service [ 'protocol' ] , service [ 'port' ]
raise StopIteration
next = __next__ # optional python2 compatibility
当我们的当前位置小于服务长度时,我们会不断遍历列表中的服务,但只有在服务处于活动状态时才返回。 一旦我们用完了要迭代的服务,就会引发
StopIteration异常。
因为我们实现了__next__()
方法,该方法在耗尽时会引发StopIteration
,所以我们可以从__iter__()
返回self
,因为IterableServer
类遵循iterable
协议。
现在,我们可以遍历IterableServer
的实例,这将使我们能够查看每个活动的服务,如下所示:
>>> for protocol , port in IterableServer ( ) :
print ( 'service %s is running on port %d' % ( protocol , port ) )
service ssh is running on port 22
service http is running on port 21
很好,但是我们可以做得更好! 在这样的实例中,我们的迭代器不需要维护很多状态,我们可以简化代码,而使用生成器 。
class Server:
services = [
{ 'active' : False , 'protocol' : 'ftp' , 'port' : 21 } ,
{ 'active' : True , 'protocol' : 'ssh' , 'port' : 22 } ,
{ 'active' : True , 'protocol' : 'http' , 'port' : 21 } ,
]
def __iter__ ( self ) :
for service in self . services :
if service [ 'active' ] :
yield service [ 'protocol' ] , service [ 'port' ]
yield
关键字到底是什么? 在定义生成器函数时使用收益。 这有点像return
。 当return
值返回值后退出函数时, yield
暂停执行直到下一次调用它为止。 这使您的生成器功能可以保持状态,直到恢复为止。 查看yield的文档以了解更多信息。 使用生成器,我们不必通过记住位置来手动维护状态。 生成器只知道两件事:它现在需要做什么以及计算下一项需要做什么。 一旦达到了不再调用yield
的执行点,我们就知道要停止迭代。
由于某些内置的Python魔术,此方法有效。 在__iter__()
的Python文档中,我们可以看到,如果__iter__()
被实现为生成器,它将自动返回提供__iter__()
和__next__()
方法的迭代器对象。 阅读这篇精彩的文章,深入了解迭代器,可迭代对象和生成器 。
方法魔术
由于其独特的方面,Python提供了一些有趣的方法魔术作为语言的一部分。
别名函数就是一个例子。 由于函数只是对象,因此我们可以将它们分配给多个变量。 例如:
>>> def foo ( ) :
return 'foo'
>>> foo ( )
'foo'
>>> bar = foo
>>> bar ( )
'foo'
稍后我们将介绍如何使用它。
Python提供了一个方便的内置方法, 称为
getattr() ,它接受object, name, default
参数并返回object
的属性name
。 这以编程方式允许我们访问实例变量和方法。 例如:
>>> class Dog:
sound = 'Bark'
def speak ( self ) :
print ( self . sound + '!' , self . sound + '!' )
>>> fido = Dog ( )
>>> fido. sound
'Bark'
>>> getattr ( fido , 'sound' )
'Bark'
>>> fido. speak
< bound method Dog. speak of < __main__ . Dog object at 0x102db8828 >>
>>> getattr ( fido , 'speak' )
< bound method Dog. speak of < __main__ . Dog object at 0x102db8828 >>
>>> fido. speak ( )
Bark ! Bark !
>>> speak_method = getattr ( fido , 'speak' )
>>> speak_method ( )
Bark ! Bark !
很酷的技巧,但实际上如何使用
getattr ? 让我们看一个示例,该示例允许我们编写一个微型命令行工具来动态处理命令。
class Operations:
def say_hi ( self , name ) :
print ( 'Hello,' , name )
def say_bye ( self , name ) :
print ( 'Goodbye,' , name )
def default ( self , arg ) :
print ( 'This operation is not supported.' )
if __name__ == '__main__' :
operations = Operations ( )
# let's assume we do error handling
command , argument = input ( '> ' ) . split ( )
func_to_call = getattr ( operations , command , operations. default )
func_to_call ( argument )
我们的脚本的输出是:
$ python getattr.py
> say_hi Nina
Hello, Nina
> blah blah
This operation is not supported.
接下来,我们看一下
partial 。 例如, functool.partial(func, *args, **kwargs)
允许您返回一个新的局部对象 ,该对象的行为类似于使用args
和kwargs
调用的func
。 如果有更多的args
传入,则将它们附加到args
。 如果传入更多kwargs
,它们将扩展并覆盖kwargs
。 让我们通过一个简单的示例来看看它的作用:
>>> from functools import partial
>>> basetwo = partial ( int , base = 2 )
>>> basetwo
< functools. partial object at 0x1085a09f0 >
>>> basetwo ( '10010' )
18
# This is the same as
>>> int ( '10010' , base = 2 )
让我们看看这种方法如何与我喜欢使用的名为
agithub
的库中的一些示例代码紧密联系在一起,这是一个(名称不正确的)REST API客户端,具有透明的语法,允许您以最少的费用快速原型化任何REST API(不仅仅是GitHub)组态。 我觉得这个项目很有趣,因为它功能强大,但只有大约400行Python。 您可以在大约30行配置代码中添加对任何REST API的支持。 agithub
知道它需要有关协议的所有信息( REST
, HTTP
, TCP
),但是它不假设上游API。 让我们深入研究实现。
这是我们为GitHub API和任何其他相关连接属性定义端点URL的简化版本。 查看完整的代码 。
class GitHub ( API ) :
def __init__ ( self , token = None , *args , **kwargs ) :
props = ConnectionProperties ( api_url = kwargs. pop ( 'api_url' , 'api.github.com' ) )
self . setClient ( Client ( *args , **kwargs ) )
self . setConnectionProperties ( props )
然后,在配置了访问令牌后 ,就可以开始使用GitHub API了 。
>>> gh = GitHub ( 'token' )
>>> status , data = gh. user . repos . get ( visibility = 'public' , sort = 'created' )
>>> # ^ Maps to GET /user/repos
>>> data
... [ 'tweeter' , 'snipey' , '...' ]
请注意,正确拼写取决于您。 没有验证URL。 如果网址不存在或其他任何错误,则将返回API引发的错误。 那么,这一切如何运作? 让我们弄清楚。 首先,我们将检查
API类的简化示例:
class API:
# ... other methods ...
def __getattr__ ( self , key ) :
return IncompleteRequest ( self . client ) . __getattr__ ( key )
__getitem__ = __getattr__
API
类的每次调用都将对指定key
的调用转移到IncompleteRequest
类 。
class IncompleteRequest:
# ... other methods ...
def __getattr__ ( self , key ) :
if key in self . client . http_methods :
htmlMethod = getattr ( self . client , key )
return partial ( htmlMethod , url = self . url )
else :
self . url + = '/' + str ( key )
return self
__getitem__ = __getattr__
class Client:
http_methods = ( 'get' ) # ... and post, put, patch, etc.
def get ( self , url , headers = { } , **params ) :
return self . request ( 'GET' , url , None , headers )
如果最后一次调用不是HTTP方法(例如“ get”,“ post”等),则它将返回带有附加路径的
IncompleteRequest 。 否则,它将从Client
类中获取用于指定HTTP方法的正确函数,并返回partial
。
如果我们给出一条不存在的路径会怎样?
>>> status , data = this. path . doesnt . exist . get ( )
>>> status
... 404
并且因为
__getitem__别名为__getattr__
:
>>> owner , repo = 'nnja' , 'tweeter'
>>> status , data = gh. repos [ owner ] [ repo ] . pulls . get ( )
>>> # ^ Maps to GET /repos/nnja/tweeter/pulls
>>> data
.... # {....}
现在这是一些严肃的方法魔术!
学到更多
Python提供了许多工具,可让您使代码更优雅,更易于阅读和理解。 挑战在于找到适合该工作的工具,但我希望本文能为您的工具箱添加一些新工具。 而且,如果您想更进一步,可以在我的博客nnja.io上阅读有关装饰器,上下文管理器,上下文生成器和
NamedTuple的信息 。 当您成为一名更好的Python开发人员时,我鼓励您到那里来阅读结构良好的项目的一些源代码。 Request和Flask是两个很好的代码库。
要了解有关这些主题以及装饰器,上下文管理器,上下文装饰器和NamedTuples的更多信息,请在PyCon Cleveland 2018上参加Nina Zakharenko的演讲`` 日常Python问题的优雅解决方案 ''。
翻译自: https://opensource.com/article/18/4/elegant-solutions-everyday-python-problems
python 日志解决方案
python 日志解决方案_日常Python问题的绝佳解决方案相关推荐
- python 时间序列预测_使用Python进行动手时间序列预测
python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...
- python 概率分布模型_使用python的概率模型进行公司估值
python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...
- python集群_使用Python集群文档
python集群 Natural Language Processing has made huge advancements in the last years. Currently, variou ...
- python 网页编程_通过Python编程检索网页
python 网页编程 The internet and the World Wide Web (WWW), is probably the most prominent source of info ...
- python编写代码_用 Python 编写干净、可测试、高质量的代码
用 Python 编写干净.可测试.高质量的代码 Noah Gift 2010 年 12 月 20 日发布 简介 编写软件是人所承担的最复杂的任务之一.AWK 编程语言和 "K and R ...
- python 免费空间_用python做大数据
不学Python迟早会被淘汰?Python真有这么好的前景? 最近几年Python编程语言在国内引起不小的轰动,有超越Java之势,本来在美国这个编程语言就是最火的,应用的非常非常的广泛,而Pytho ...
- python培训班-Python培训机构_高品质Python线下开发培训班推荐-黑马程序员
Python编程基础基础班1 课时:15天技术点:97项测验:2次学习方式:线下面授 学习目标 1.掌握Python开发环境基本配置|2.掌握运算符.表达式.流程控制语句.数组等的使用|3.掌握字符串 ...
- python 创意项目_针对python开发人员的10个很棒的python项目创意
python 创意项目 The joy of coding Python should be in seeing short, concise, readable classes that expre ...
- python psycopg2使用_安装python依赖包psycopg2来调用postgresql的操作
1.先安装psycopg2的依赖组件 本案例的操作系统为linux red hat 在安装python依赖包psycopg之前,你必须需要先安装postgresql数据库的相关组件: postgres ...
最新文章
- WPF:如何为程序添加splashScreen(初始屏幕)
- 数据库连接池之_DButils
- Linux基础之-网络配置,主机名设置,ssh登陆,scp传输
- mac自带python怎么用_怎么在mac上使用python
- LeetCode MySQL 1126. 查询活跃业务
- PHP操作图片简单案例
- ASP.NET Web API 配置 JSONP
- mysql 执行 毫秒_记录sql执行时间毫秒级
- html字体样式(有中文兼英文实例)
- Postgresql动态执行EXECUTING语法解析过程
- 海风教育荣获第七届中国财经峰会最具成长价值奖
- cuba study
- 足够的需求,总归有蹒跚的第一步—“Holle,world!”
- h5 视频播放功能实现
- 阿里云使用笔记-第三篇-使用阿里云App连接实例
- 民间房产抵押借贷 房子说收就收你信吗?
- PHP使用者,使用C#完成需求,遇到思路和问题
- AAAI 2022 | 量化交易相关论文(附论文链接)
- nRF51822-新手入门笔记
- 推荐一个免费获得Q币的方法!