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实例在不同端口上运行不同服务(例如httpssh的场景。 其中一些服务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)允许您返回一个新的局部对象 ,该对象的行为类似于使用argskwargs调用的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知道它需要有关协议的所有信息( RESTHTTPTCP ),但是它不假设上游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问题的绝佳解决方案相关推荐

  1. python 时间序列预测_使用Python进行动手时间序列预测

    python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...

  2. python 概率分布模型_使用python的概率模型进行公司估值

    python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...

  3. python集群_使用Python集群文档

    python集群 Natural Language Processing has made huge advancements in the last years. Currently, variou ...

  4. python 网页编程_通过Python编程检索网页

    python 网页编程 The internet and the World Wide Web (WWW), is probably the most prominent source of info ...

  5. python编写代码_用 Python 编写干净、可测试、高质量的代码

    用 Python 编写干净.可测试.高质量的代码 Noah Gift 2010 年 12 月 20 日发布 简介 编写软件是人所承担的最复杂的任务之一.AWK 编程语言和 "K and R ...

  6. python 免费空间_用python做大数据

    不学Python迟早会被淘汰?Python真有这么好的前景? 最近几年Python编程语言在国内引起不小的轰动,有超越Java之势,本来在美国这个编程语言就是最火的,应用的非常非常的广泛,而Pytho ...

  7. python培训班-Python培训机构_高品质Python线下开发培训班推荐-黑马程序员

    Python编程基础基础班1 课时:15天技术点:97项测验:2次学习方式:线下面授 学习目标 1.掌握Python开发环境基本配置|2.掌握运算符.表达式.流程控制语句.数组等的使用|3.掌握字符串 ...

  8. python 创意项目_针对python开发人员的10个很棒的python项目创意

    python 创意项目 The joy of coding Python should be in seeing short, concise, readable classes that expre ...

  9. python psycopg2使用_安装python依赖包psycopg2来调用postgresql的操作

    1.先安装psycopg2的依赖组件 本案例的操作系统为linux red hat 在安装python依赖包psycopg之前,你必须需要先安装postgresql数据库的相关组件: postgres ...

最新文章

  1. WPF:如何为程序添加splashScreen(初始屏幕)
  2. 数据库连接池之_DButils
  3. Linux基础之-网络配置,主机名设置,ssh登陆,scp传输
  4. mac自带python怎么用_怎么在mac上使用python
  5. LeetCode MySQL 1126. 查询活跃业务
  6. PHP操作图片简单案例
  7. ASP.NET Web API 配置 JSONP
  8. mysql 执行 毫秒_记录sql执行时间毫秒级
  9. html字体样式(有中文兼英文实例)
  10. Postgresql动态执行EXECUTING语法解析过程
  11. 海风教育荣获第七届中国财经峰会最具成长价值奖
  12. cuba study
  13. 足够的需求,总归有蹒跚的第一步—“Holle,world!”
  14. h5 视频播放功能实现
  15. 阿里云使用笔记-第三篇-使用阿里云App连接实例
  16. 民间房产抵押借贷 房子说收就收你信吗?
  17. PHP使用者,使用C#完成需求,遇到思路和问题
  18. AAAI 2022 | 量化交易相关论文(附论文链接)
  19. nRF51822-新手入门笔记
  20. 推荐一个免费获得Q币的方法!

热门文章

  1. Elasticsearch-head插件的安装与使用
  2. rocketMq发送事务消息
  3. Sphinx+Scws 搭建千万级准实时搜索应用场景详解
  4. 实战Spring Boot 2.0系列(一) - 使用Gradle构建Docker镜像
  5. Spring Cloud在云计算SaaS中的实战经验分享
  6. easyui datagrid 单元格内文本超出长度显示省略号
  7. javascript在asp.net中运用
  8. 程序员的进阶课-架构师之路(8)-二叉树
  9. 程序员的进阶课-架构师之路(6)-链表
  10. 深入理解Transformer及其源码