@[TOC]

字符串表示形式

str()

方便阅读

repr()

方便调试

  • repr 返回对象的官方表示形式
  • print 用于打印可读性好的字符串
  • str 返回对象的非正式表示
  • eval 用于执行字符串表示的代码。
  • 在字符串示例中,由于字符串中包含引号和全角逗号,因此在 repr 和 str 的输出中会反映这些差异,但 eval 用于执行这些字符串时,它们被正确处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14

>>> from fractions import Fraction
>>> half= Fraction(12)
>>> halfFraction(12)
>>>> repr(half)
'Fraction(1,2)'
>>> print(half)
1/2
>>> str(half)
'1/2'
>>> eval(repr(half))
Fraction(12)
>>> eval(str(half))
05

repr(half) 返回对象的”official”字符串表示形式,它是 Fraction(1,2),它是有效的Python表达式,可以用于重建相同的对象。
print(half) 打印对象时,print 使用对象的 str 方法,所以它输出 ‘1/2’,这是用户友好的字符串表示。
str(half) 返回对象的”informal”字符串表示形式,这里返回 ‘1/2’。
eval(repr(half)) 使用 eval 函数来执行 repr(half) 返回的字符串,这将返回一个新的 Fraction 对象,即 Fraction(1,2)。
eval(str(half)) 使用 eval 函数来执行 str(half) 返回的字符串,这将返回浮点数 0.5,因为 eval 解释它为数学表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> s = "Hello, World"
>>>s
'Hello,World'
>>> print(repr(s))
'Hello,World'
>>> print(s)
Hello,World
>>> print(str(s))
Hello,World
>>> str(s)
'Hello,World'
>>> repr(s)
"'Hello,World'"
>>> eval(repr(s))
'Hello,World'
>>> repr(repr(repr(s)))
'\'"\\\'Hello,world\\\'"\''
>>> eval(eval(eval(repr(repr(repr(s)))))))
'Hello, World'

字符串插值

f’{}’

花括号里的为Python表达式 会自动计算
你也可以用str()或repr()

多态函数

使用于许多不同类型数据的函数
str和repr函数就是例子

例子

repr

调用一个零参数方法,相应地称为__repr__

1
2
>>> half.__repr__()
'Fraction(1, 2)'

str

调用一个零参数方法,相应地称为_str_

1
2
3

>>> half.__str__()
'1/2'

使用print()时实际上就是调用了__str__()

repr和str的实现

1
2
def repr(x):
return type(x).__repr__(x)

通过查找为你提供的参数类型来设法跳过实例属性或忽略他们

是一个类属性,也是一个函数,但是这个函数不是绑定方法,因为它是在type类中查找的

接口

  • 对象属性是消息传递的一种形式,它允许不同的数据类型以不同的方式响应同一消息。

对象通过发送消息(通常是方法调用)来与其他对象进行交互。对象的属性可以是对象的状态或数据。

  • 从不同类引出类似行为的一组共享消息是一种强大的抽象方法。

不同的类可以实现相同的接口或共享相同的消息。

  • 接口是一组共享属性名称,以及它们的行为规范。在复数的情况下,实现算术所需的接口由四个属性组成: real 、 imag 、 magnitude 和 angle 。

    这是一个具体的示例,说明了接口的用途。如果多个类需要实现某种算术操作(例如复数的加法或乘法),可以定义一个接口,其中包含所需的属性名称和方法,以确保这些类都具有相同的接口,从而可以执行相似的操作。

消息传递:对象通过查找彼此的属性(传递消息)进行交互
属性查找规则允许不同的数据类型响应相同的消息
从不同对象类中引出类似行为的共享消息(属性名)是一种强大的抽象方法

实现返回python可解释和人类可读字符串的方法实现了用于生成字符串表示的接口

1
2
3
4
5
6
7
8
9
10
class Ratio:
def __init__(self, n , d):
self.numer = n
self.denom = d

def __repr__(self):
return 'Ratio({0}, {1})'.format(self.numer, self.denom)

def __str__(self):
return '{0}/{1}'.format(self.numer, self.denom)
1
2
3
4
5
6

>>> half = Ratio(1, 2)
>>> print(half)
1/2
>>> half
Ratio(1, 2)

个人对接口的理解:有一些具有相同行为的类,我们定义了一个接口,使得我们不需要知道传入这些类中的数据类型便知道这些类都有一种可以计算某个结果的方法。这样子不管什么数据类型都可以计算出我们需要的预期结果。[这是抽象接口]

Python存在两种接口 一个是面对对象用于继承的抽象接口,一个是用于封装类显露出来的动态接口[下面Ratio类的add方法是一种接口,是动态接口]

特殊方法名称

总是有__在前面和后面

1
2
3
4
5
>>>zero, one, two = 0, 1, 2
>>> one + two
3
>>> bool(zero), bool(one)
(False, True)
1
2
3
4
5
6

>>>zero, one, two = 0, 1, 2
>>> one.__add__(two)
3
>>> zero.__bool__(), one.__bool__()
(False, True)

内置语法和内置函数 与 实际执行工作的特殊方法名称中间存在对应关系

这是使用接口来允许用户定义的对象与Python中内置系统进行交互的另一个示例。
我们举例类的时候可以覆盖特殊方法来建立我们想要的互动结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Ratio:
def __init__(self, n , d):
self.numer = n
self.denom = d

def __repr__(self):
return 'Ratio({0}, {1})'.format(self.numer, self.denom)

def __str__(self):
return '{0}/{1}'.format(self.numer, self.denom)

def __add__(self, other):
if isinstance(other, int):
n = self.numer + self.denom * other
d = self.denom
elif isinstance(other, Ratio):
n = self.numer * other.denom + self.denom * other.numer
d = self.denom * other.denom
elif isinstance(other, float):
return float(self) + other
g = gcd(n, d)
return Ratio(n//g, d//g)
__radd__ = __add__

def __float__(self):
return self.numer/self.denom
def gcd(n, d):
while n != d:
n, d = min(n, d), abs(n - d)
return n
  • 类型分类:用了条件语句对传入的other数据类型进行判断从而提供不同的执行方法
  • 类型强制:将一种类型的对象转换为另一种类型,以便能够将其与其他值组合。

这是让两个类进行交互时而使用的两种策略

__add__函数相当于是一个隐形接口,我们不需要知道传入的数据是不是浮点数、整数还是什么,都可以将他们加起来