【问题标题】:Adding a decorator that converts strings to lowercase in Python在 Python 中添加一个将字符串转换为小写的装饰器
【发布时间】:2013-10-22 03:15:39
【问题描述】:

所以我是学习装饰器的新手,我已经阅读了无数教程,虽然我理解并且几乎可以遵循所有示例,但我认为最好的学习方式是自己实现装饰器。所以我将在下面使用这个例子。我意识到装饰器根本不需要这样做,但是为了学习,我想添加一个装饰器来过滤像狗名和品种这样的字符串并将它们变成小写。任何正确方向的想法或指示将不胜感激。

class Dogs:
    totalDogs = 0
    dogList=[]

    def __init__(self, breed, color, age):
        self.breed=breed
        self.color=color
        self.age=age
        Dogs.dogList.append(self.breed)
        Dogs.totalDogs += 1

    def displayDogs(self):
        print "breed: ", self.breed
        print "color: ",self.color
        print "age: ",self.age
        print "list of breeds:", Dogs.dogList
        print "total dogs: ", Dogs.totalDogs

def somedecorator(*args):
    #now what

terrier=Dogs("TeRrIer", "white", 5)
terrier.displayDogs()
retriever=Dogs("goldenRETRIEVER", "brown", 10)
retriever.displayDogs()

【问题讨论】:

  • 您正在寻找的输出究竟是什么?它是不是像 string.lower() 函数一样只是小写,但你想使用 ascii 值来实现它?
  • 嗯,我不太确定你刚才问的是什么。澄清一下,这些对我来说都不重要,我真的只是想实现某种装饰器来了解更多关于装饰器的信息。
  • 如果你想进入比特级别,这篇文章应该可以帮助stackoverflow.com/questions/3569874/…
  • 我并不是在寻求有关如何输出小写字符串的帮助,我是在寻求实现装饰器的帮助。我不知道从哪里开始装饰器本身,我对如何调用它感到困惑。例如我把它放在 displayDogs() 还是 terrier.displayDogs()
  • 装饰器用于修改函数。例如,如果你有“getDogInfo(self)”返回一个描述所有狗的字符串,你可以有一个装饰器来修改它的返回值并使其变为小写或其他东西。在装饰器中最容易做的事情是 1) 在原始函数之前添加代码,2) 在原始函数之后添加代码,以及 3) 带有函数参数的 Monkey。所以在函数中修改打印状态就有点困难了。

标签: python python-decorators


【解决方案1】:

装饰器实际上只是一个将函数作为参数并返回另一个函数的函数。

def lower_output(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs).lower()
    return wrapper


class Dogs(object):
    totalDogs = 0
    dogList=[]

    def __init__(self, breed, color, age):
        self.breed=breed
        self.color=color
        self.age=age
        Dogs.dogList.append(self.breed)
        Dogs.totalDogs += 1

    @lower_output
    def get_breed(self):
        return self.breed




>>> terrier=Dogs("TeRrIer", "white", 5)
>>> terrier.get_breed()
terrier

【讨论】:

  • 感谢您的帮助,尽管我收到一条错误消息,提示第 12 行 lower_output 未定义
  • 尝试在模块中进一步定义它,我已经为你编辑了我的示例。
【解决方案2】:

好吧,为了简化它,让我们首先处理函数。假设您有一个函数可以打印有关其参数的内容:

def print_info(breed, name):
    print "The doggie %s's breed is %s." % (name, breed)

这样:

>>> print_info("Labrador", "Spike")
The doggie Spike's breed is Labrador.
>>> print_info("Pit Bull", "Spot")
The doggie Spot's breed is Pit Bull.

现在您希望该函数始终将品种小写。因此,以一种理智的方式,您只需这样做:

def manually_lowered_print_info(breed, name):
    print "The doggie %s's breed is %s." % (name, breed.lower())

输出是:

>>> manually_lowered_print_info("Labrador", "Spike")
The doggie Spike's breed is labrador.

但是假设由于某种原因,您经常不得不将您编写的函数的第一个字符串参数小写,因此您想将其抽象为装饰器。我们希望它看起来像这样并具有相同的输出:

@lower_first_arg
def dec_lowered_print_info(breed, name):
    print "The doggie %s's breed is %s." % (name, breed)

这只是语法糖:

def tmp_func(breed, name):
    print "The doggie %s's breed is %s." % (name, breed)
dec_lowered_print_info = lower_first_arg(tmp_func)

所以我们希望lower_first_arg返回转换后的print_info 函数。我们先做一个专门为print_info函数量身定制的函数。

def lower_first_arg(print_info_func_arg):
    def inner_print_info(breed, name):
        return print_info_func_arg(breed.lower(), name)
    return inner_print_info

有效吗?让我们看看:

>>> transformed_print_info = lower_first_arg(print_info)
>>> print_info("Pit Bull", "Spot")
The doggie Spot's breed is Pit Bull.
>>> transformed_print_info("Pit Bull", "Spot")
The doggie Spot's breed is pit bull.

太棒了!请注意,我们将print_info 作为参数传递给lower_first_arg 函数,它被局部变量print_info_func_arg 引用。

如果我们使用装饰器语法,它的工作原理是一样的:

@lower_first_arg
def dec_lowered_print_info(breed, name):
    print "The doggie %s's breed is %s." % (name, breed)

优秀:

>>> dec_lowered_print_info("Pit Bull", "Spot")
The doggie Spot's breed is pit bull.

很酷,就是这样,真的。现在为了让装饰器更通用,让我们先概括一下名称:

def generic_lower_first_arg(f):
    def wrapped(arg1, arg2):
        return f(arg1.lower(), arg2)
    return wrapped

现在这里的问题是这个装饰器只适用于 2 个参数的函数。理想情况下,我们希望它适用于 1 arg 或更多的任何函数,例如:

@generic_lower_first_arg
def failed_whatnow(first, last, middle):
    print "%s %s %s" % (first, middle, last)

现在,该代码将运行,但如果我们尝试调用它,则会出现错误:

>>> failed_whatnow("Bob", "Jones", "The Killer")

Traceback (most recent call last):
  File "<pyshell#26>", line 1, in <module>
    failed_whatnow("Bob", "Jones", "The Killer")
TypeError: wrapped() takes exactly 2 arguments (3 given)

发生了什么事?好吧,装饰器接受了failed_whatnow 并返回了它定义的函数wrapped,但是wrapped 函数只需要两个参数!这里的修复是使用可变参数语法。传递任何可能提供给包装函数的关键字参数通常也是一个好主意。

def proper_lower_first_arg(f):
    def wrapped(arg1, *args, **kwargs):
        return f(arg1.lower(), *args, **kwargs)
    return wrapped

现在它适用于各种功能:

@proper_lower_first_arg
def proper_whatnow(first, last, middle):
    print "%s %s %s" % (first, middle, last)

@proper_lower_first_arg
def multiplyit(mm, n=3):
    return mm * n

证明:

>>> proper_whatnow("Bob", "Jones", "The Killer")
bob The Killer Jones
>>> multiplyit("HaHa.Fool!")
'haha.fool!haha.fool!haha.fool!'
>>> multiplyit("HaHa.Fool!", n=5)
'haha.fool!haha.fool!haha.fool!haha.fool!haha.fool!'

【讨论】:

    【解决方案3】:

    装饰器通常用于修改函数/方法的输入参数或返回值。

    方法Dogs.displayDogs 不返回任何数据(None 除外),所以说你想让字符串小写是没有意义的。哪些字符串?您只需打印值。所以你会这样做:

    class Dogs:
        totalDogs = 0
        dogList=[]
    
        def __init__(self, breed, color, age):
            self.breed=breed
            self.color=color
            self.age=age
            Dogs.dogList.append(self.breed)
            Dogs.totalDogs += 1
    
        def displayDogs(self):
            print "breed: ", self.breed.lower()
            print "color: ",self.color.lower()
            ...
    

    否则你应该重构你的代码:

    def make_lower(func):
        def wrapper(*args, **kwargs):
            result = func(*args, **kwargs)
            result = [value.lower() for value in result]
            return result
        return wrapper
    
    class Dogs:
        totalDogs = 0
        dogList=[]
    
        def __init__(self, breed, color, age):
            self.breed=breed
            self.color=color
            self.age=age
            Dogs.dogList.append(self.breed)
            Dogs.totalDogs += 1
    
    
        @make_lower
        def getDogs(self):
            return [
                "breed: %s" % self.breed,
                "color: %s" % self.color.lower(),
                ...
            ]
    

    你做的

    terrier = Dogs("TeRrIer", "white", 5)
    print terrier.getDogs()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-03
      • 1970-01-01
      相关资源
      最近更新 更多