不能使用partial作为__str__

时间:2017-09-24 03:56:05

标签: python namedtuple

我在尝试为程序编写一个漂亮的打印过程时遇到了这个问题,在这个程序中我使用了几个包含浮点对的命名元组。

ALTER PROCEDURE [dbo].[MyStoredProcedure]
(
    @FromYears              NVARCHAR(MAX), // will be 2005$Format2009$Format2013
    @ToYears                NVARCHAR(MAX), // will be 2008$Format2012$Format2017
    @CompanyAddresses       NVARCHAR(MAX), // will be string$Formatstring$Formatstring
    @ProgrammingLanguages   NVARCHAR(MAX), // will be Javascript$FormatC++$FormatC#
    @MemberAddress          NVARCHAR(MAX),
    @FullName               NVARCHAR(MAX),
    @BirthDate              DATETIME,
    @TelephoneNumber        NVARCHAR(MAX)
)
AS
BEGIN
    DECLARE
        @MemberCount            INT,
        @FromYear               INT,
        @ToYear                 INT,
        @CompanyAddress         NVARCHAR(MAX),
        @ProgrammingLanguage    NVARCHAR(MAX)

    DECLARE @FromYearTable      TABLE (
        [ID]            INT         IDENTITY,
        [FromYear]      INT         NOT NULL
    )

    DECLARE @ToYearTable        TABLE (
        [ID]            INT         IDENTITY,
        [ToYear]        INT         NOT NULL
    )

    DECLARE @CompanyAddressTable        TABLE (
        [ID]                INT             IDENTITY,
        [CompanyAddress]    NVARCHAR(MAX)   NOT NULL
    )

    DECLARE @ProgrammingLanguageTable           TABLE (
        [ID]                    INT             IDENTITY,
        [ProgrammingLanguage]   NVARCHAR(MAX)   NOT NULL
    )

    DECLARE @MemberTable            TABLE (
        [ID]                    INT             IDENTITY,
        [FromYear]              INT             NOT NULL,
        [ToYear]                INT             NOT NULL,
        [CompanyAddress]        NVARCHAR(MAX)   NOT NULL,
        [ProgrammingLanguage]   NVARCHAR(MAX)   NOT NULL
    )

    INSERT INTO @FromYearTable
    SELECT [SplittedItem] FROM [StringSplit] (@FromYears, '$Format')

    INSERT INTO @ToYearTable
    SELECT [SplittedItem] FROM [StringSplit] (@ToYears, '$Format')

    INSERT INTO @CompanyAddressTable
    SELECT [SplittedItem] FROM [StringSplit] (@CompanyAddresses, '$Format')

    INSERT INTO @ProgrammingLanguageTable
    SELECT [SplittedItem] FROM [StringSplit] (@ProgrammingLanguages, '$Format')

    INSERT INTO @MemberTable
    SELECT a.[FromYear], b.[ToYear], c.[CompanyAddress], d.[ProgrammingLanguage]
    FROM @FromYearTable a
    INNER JOIN @ToYearTable b ON a.[ID] = b.[ID]
    INNER JOIN @CompanyAddressTable c ON a.[ID] = c.[ID]
    INNER JOIN @ProgrammingLanguageTable d ON a.[ID] = d.[ID]

    /*
        Will be like:
        ID  FromYear    ToYear  CompanyAddress  ProgrammingLanguage
        1   2005        2008    string          Javascript
        2   2009        2012    string          C++
        3   2013        2017    string          C#
    */

    SET @MemberCount = (SELECT COUNT(*) FROM @MemberTable)

    WHILE (@MemberCount > 0)
    BEGIN
        SET @FromYear = (SELECT TOP 1 [FromYear] FROM @MemberTable WHERE [ID] = @MemberCount)
        SET @ToYear = (SELECT TOP 1 [ToYear] FROM @MemberTable WHERE [ID] = @MemberCount)
        SET @CompanyAddress = (SELECT TOP 1 [CompanyAddress] FROM @MemberTable WHERE [ID] = @MemberCount)
        SET @ProgrammingLanguage = (SELECT TOP 1 [ProgrammingLanguage] FROM @MemberTable WHERE [ID] = @MemberCount)

        INSERT INTO [MyTable] (@FromYear, @ToYear, @CompanyAddress, @ProgrammingLanguage, @MemberAddress, @FullName, @BirthDate, @TelephoneNumber)

        SET @MemberCount -= 1
    END
END

我想在打印时格式化浮点数,因为结果为:

from collections import namedtuple
Position = namedtuple('Position', 'x y')
Vector = namedtuple('Vector', 'x y')
Size = namedtuple('Size', 'width height')

太长了:

import math
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))

所以我创建了一个打印命名元组的函数:

Position(x=3.141592653589793, y=3.141592653589793) Vector(x=3.141592653589793, y=3.141592653589793) Size(width=3.141592653589793, height=3.141592653589793)

每个类型的名称和标签都应该是固定的,只有obj参数不同,所以我认为我可以使用functools partial。

def pretty_float_pair(name, labels, obj):
    """
    If labels = ('a', 'b') and object = (1.2345, 1.2345) returns:
        'name(a=1.23, b=1.23)'
    """
    return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1])

但这会引发from functools import partial Position.__str__ = partial(pretty_float_pair, 'Position', ('x', 'y')) Vector.__str__ = partial(pretty_float_pair, 'Vector', ('x', 'y')) Size.__str__ = partial(pretty_float_pair, 'Size', ('width', 'height')) print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))

令人惊讶的是,如果我使用lambda创建它可以运行的函数。

TypeError: pretty_float_pair() missing 1 required positional argument: 'obj'.

打印我想要的东西:

Position.__str__ = lambda x: pretty_float_pair('Position', ('x', 'y'), x)
Vector.__str__ = lambda x: pretty_float_pair('Vector', ('x', 'y'), x)
Size.__str__ = lambda x: pretty_float_pair('Size', ('width', 'height'), x)
print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))

我试图理解为什么部分版本不起作用。

2 个答案:

答案 0 :(得分:3)

functools.partial返回非描述符可调用,大致相当于未绑定方法。这意味着它没有传递self参数,这与您看到的错误一致。

由于lambda的行为与使用def定义的常规函数​​一样,因此它实际上是一个描述符。 lambda的__get__方法返回一个绑定版本,该版本在实例中传递为x

要获得行为更像方法的部分函数,​​请改用functools.partialmethod。您必须将obj移动到参数列表的开头,以便在绑定方法时接收self

以下是您的示例:

from functools import partialmethod

def pretty_float_pair(obj, name, labels):
    """
    If labels = ('a', 'b') and object = (1.2345, 1.2345), returns:
        name(a=1.23, b=1.23)
    """
    return '{}({}={:.2f}, {}={:.2f})'.format(name, labels[0], obj[0], labels[1], obj[1])

Position.__str__ = partialmethod(pretty_float_pair, 'Position', ('x', 'y'))
Vector.__str__ = partialmethod(pretty_float_pair, 'Vector', ('x', 'y'))
Size.__str__ = partialmethod(pretty_float_pair, 'Size', ('width', 'height'))

print(Position(math.pi, math.pi), Vector(math.pi, math.pi), Size(math.pi, math.pi))

答案 1 :(得分:1)

函数通过descriptors获取其隐式self参数:lookup x.f构造并返回一个记住x的方法对象,以便将其提供给{{1} }}。 f不返回描述符,因此它没有得到特殊处理。 (它实际上是一个类,所以它"返回"它自己的一个实例。)