python中的点表示什么_什么是“ 1 ..__ truediv__”? Python是否具有..(“点点”)表示法语法?...

最近,我遇到了一种在学习python之前从未见过的语法,在大多数教程中,..表示法看起来像这样:

1

2

3f = 1..__truediv__ # or 1..__div__ for python 2

print(f(8)) # prints 0.125

我发现它和(当然,它更长)完全一样:

1

2f = lambda x: (1).__truediv__(x)

print(f(8)) # prints 0.125 or 1//8

但是我的问题是:

它怎么做呢?

这两个点实际上意味着什么?

如何在更复杂的语句中使用它(如果可能)?

将来可能会为我节省很多代码行... :)

注意:(1).__truediv__与1..__truediv__并不完全相同,因为前者调用int.__truediv__,而后者调用float.__truediv__。另外,您也可以使用1 .__truediv__(带空格)`。

请注意,在任一版本的Python中,18是0,而不是0.125。

让我想起if (x

这是一个正在使用的示例。

如果您要编写lambda,请写lambda x: 1x,这是一个较短的字符(如果您需要1.x,则长度相同)。涉及显式调用__method__的任何事情(在覆盖此类方法的派生类之外)属于"愚蠢的python技巧"类别-很有意思,但几乎可以肯定不属于生产代码。

@PeterWood请您在评论中提供一个解释,这样可以理解为什么不应该这样做的原因?

@KeithC高质量的答案和注释表明示例代码需要洞察力才能理解,这使许多人感到惊讶,具有更清晰,更通用且至少有效的替代方法。我的主要抱怨是可读性很重要。在最需要的地方保存智慧-与人沟通。

您拥有的是一个float文字,不带尾随零,然后您可以使用其__truediv__方法。它本身不是运算符;第一个点是float值的一部分,第二个点是用于访问对象属性和方法的点运算符。

您可以通过执行以下操作达到相同的目的。

1

2

3

4

5>>> f = 1.

>>> f

1.0

>>> f.__floordiv__

另一个例子

1

2>>> 1..__add__(2.)

3.0

在这里,我们将1.0加到2.0,显然得出3.0。

因此,我们找到的是一位开发人员,为简洁起见牺牲了很多清晰度,而现在我们就在这里。

也许有人正在将其源代码保存到5.5英寸软盘上?

@ThomasAyoub应该是5.25" iirc ;-)

@jjmontes我不好,我还没有出生:p

我不明白这是如何节省时间的。 1.0+2是否更短?

@TemporalWolf他可能在最近的高尔夫代码提交中找到了它。

@BrianMcCutchon的确是:)观看他们的高尔夫很有趣

有趣的是,您也可以使用JavaScript执行此操作:1..toString()

@BrianMcCutchon糟糕,我混淆了1+2和.1+.2。 我的错。

该问题已经得到足够的答案(即@Paul Rooneys的答案),但也可以验证这些答案的正确性。

让我回顾一下现有的答案:..不是单个语法元素!

您可以检查源代码是如何"标记"的。这些标记表示代码的解释方式:

1

2

3

4

5

6

7

8

9

10>>> from tokenize import tokenize

>>> from io import BytesIO

>>> s ="1..__truediv__"

>>> list(tokenize(BytesIO(s.encode('utf-8')).readline))

[...

TokenInfo(type=2 (NUMBER), string='1.', start=(1, 0), end=(1, 2), line='1..__truediv__'),

TokenInfo(type=53 (OP), string='.', start=(1, 2), end=(1, 3), line='1..__truediv__'),

TokenInfo(type=1 (NAME), string='__truediv__', start=(1, 3), end=(1, 14), line='1..__truediv__'),

...]

因此,字符串1.解释为数字,第二个.是OP(运算符,在这种情况下为" get attribute"运算符),而__truediv__是方法名称。因此,这只是访问float 1.0的__truediv__方法。

查看生成的字节码的另一种方法是dis对其进行汇编。这实际上显示了执行某些代码时执行的指令:

1

2

3

4

5

6

7

8

9>>> import dis

>>> def f():

... return 1..__truediv__

>>> dis.dis(f)

4 0 LOAD_CONST 1 (1.0)

3 LOAD_ATTR 0 (__truediv__)

6 RETURN_VALUE

基本上说的一样。它加载常量1.0的属性__truediv__。

关于你的问题

And how can you use it in a more complex statement (if possible)?

即使您可能永远也不要这样写代码,只是因为不清楚代码在做什么。因此,请不要在更复杂的语句中使用它。我什至会走得更远,以至于您不应该在如此"简单"的语句中使用它,至少您应该使用括号将指令分开:

1f = (1.).__truediv__

这肯定会更具可读性-但类似于:

1

2

3from functools import partial

from operator import truediv

f = partial(truediv, 1.0)

会更好!

使用partial的方法还保留了python的数据模型(1..__truediv__方法没有!),可以通过以下小片段进行演示:

1

2

3

4

5

6

7

8

9

10

11

12>>> f1 = 1..__truediv__

>>> f2 = partial(truediv, 1.)

>>> f2(1+2j) # reciprocal of complex number - works

(0.2-0.4j)

>>> f2('a') # reciprocal of string should raise an exception

TypeError: unsupported operand type(s) for /: 'float' and 'str'

>>> f1(1+2j) # reciprocal of complex number - works but gives an unexpected result

NotImplemented

>>> f1('a') # reciprocal of string should raise an exception but it doesn't

NotImplemented

这是因为1. / (1+2j)不是由float.__truediv__求值,而是使用complex.__rtruediv__-operator.truediv确保正常操作返回NotImplemented时调用了反向操作,但是对< x1>直接。这种"预期行为"的丧失是您(通常)不应直接使用魔术方法的主要原因。

首先,两个点可能有点尴尬:

1f = 1..__truediv__ # or 1..__div__ for python 2

但这与写作相同:

1f = 1.0.__truediv__ # or 1.0.__div__ for python 2

因为float文字可以用三种形式编写:

1

2

3normal_float = 1.0

short_float = 1. # == 1.0

prefixed_float = .1 # == 0.1

令人惊讶的是,为什么这些有效的语法却不是1.__truediv__?

@AlexHall看到这里。 .似乎被解析为数字的一部分,然后缺少方法访问器的.。

但是由于语法笨拙且不清楚,因此应避免使用。

What is f = 1..__truediv__?

f是在值为1的float上绑定的特殊方法。特别,

11.0 / x

在Python 3中,调用:

1(1.0).__truediv__(x)

证据:

1

2

3

4class Float(float):

def __truediv__(self, other):

print('__truediv__ called')

return super(Float, self).__truediv__(other)

和:

1

2

3

4>>> one = Float(1)

>>> one/2

__truediv__ called

0.5

如果这样做:

1f = one.__truediv__

我们保留绑定到该绑定方法的名称

1

2

3

4

5

6>>> f(2)

__truediv__ called

0.5

>>> f(3)

__truediv__ called

0.3333333333333333

如果我们在一个紧密的循环中执行该点分查找,则可以节省一些时间。

解析抽象语法树(AST)

我们可以看到,解析AST的表达式可以告诉我们,我们在浮点数1.0上获得了__truediv__属性:

1

2

3>>> import ast

>>> ast.dump(ast.parse('1..__truediv__').body[0])

"Expr(value=Attribute(value=Num(n=1.0), attr='__truediv__', ctx=Load()))"

您可以从以下获得相同的结果函数:

1f = float(1).__truediv__

要么

1f = (1.0).__truediv__

扣除

我们也可以通过扣除到达那里。

让我们建立它。

1本身是int:

1

2

3

4>>> 1

1

>>> type(1)

1,之后是句点:

1

2

3

4>>> 1.

1.0

>>> type(1.)

下一个点本身就是SyntaxError,但它会在float实例上开始点分查找:

1

2>>> 1..__truediv__

没有人提到这-这是浮点数1.0上的"绑定方法":

1

2

3

4

5

6

7>>> f = 1..__truediv__

>>> f

>>> f(2)

0.5

>>> f(3)

0.33333333333333331

我们可以更容易地完成相同的功能:

1

2

3

4

5

6

7>>> def divide_one_by(x):

... return 1.0/x

...

>>> divide_one_by(2)

0.5

>>> divide_one_by(3)

0.33333333333333331

性能

divide_one_by函数的缺点是它需要另一个Python堆栈框架,这使其比绑定方法要慢一些:

1

2

3

4

5

6

7

8

9

10

11

12>>> def f_1():

... for x in range(1, 11):

... f(x)

...

>>> def f_2():

... for x in range(1, 11):

... divide_one_by(x)

...

>>> timeit.repeat(f_1)

[2.5495760687176485, 2.5585621018805469, 2.5411816588331888]

>>> timeit.repeat(f_2)

[3.479687248616699, 3.46196088706062, 3.473726342237768]

当然,如果您仅可以使用普通文字,那就更快了:

1

2

3

4

5

6>>> def f_3():

... for x in range(1, 11):

... 1.0/x

...

>>> timeit.repeat(f_3)

[2.1224895628296281, 2.1219930218637728, 2.1280188256941983]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值