PyVarObject
typedef struct {
PyObject ob_base;
Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;
内置类型:可变长度容器的底层C语言结构体
于是如果my_object是一个内置类型的实例的话 len(my_object) 会直接读取ob_size的值
for i in my_object
会隐式调用 my_object.__iter__() 或是 my_object.__getitem()
而索引的选择是range(+∞)
class MyObject:
def __init__(self, data):
self.data = data
def __getitem__(self, key):
# return self.data[key] 正常
# return key #result:无限输出1,2,3...
# return 1 #result:无限输出1
if key==0:
return 1
elif key==1:
return 2
else:
raise StopIteration #result:1,2,finished
# raise IndexError #result:1,2,finished
# 注:IndexError: list index out of range
# raise KeyError #result:1,2,KeyError
def __len__(self):
return len(self.data)
my_object = MyObject([1,2,3,4,5,6,7,8,9,10])
for i in my_object:
print(i)
print("finished")
内置序列
-
- 容器序列:可存放不同类型项(存放的是对象)
- 扁平序列:存放一种简单类型的项(存放的是值) array(‘d’,[9.46,2.08])
-
- 可变序列
不可变序列
- 可变序列
句法tips
[] () {} 中的换行会被忽略,项与项之间用",“隔开,并且会主动忽略末尾的”,",在跨行定义列表字面量时,最好在最后一项加入一个,
listcomps
x = 'ABC'
codes = [ord(x) for x in x]
x
'ABC'
codes
[65, 66, 67]
codes = [last := ord(c) for c in x]
last
67
#x 依旧不变
#last 依旧可以访问(见下)
#c 消失了,只存在于列表推导式内部
and
In [1]: a=1
In [2]: b=2
In [3]: c=(a==1 and b)
In [4]: c
Out[4]: 2
如果and第一项为真
那么第二项将直接被赋值
walrus operator
Starting in Python 3.8, you can!
Assignment expressions using the walrus operator ``:=`` assign a variable in an
expression::
while chunk := fp.read(200):
print(chunk)
See :pep:`572` for more information.
注:似乎有点类似c语言赋值语句也是有返回值的
# Handle a matched regex
if (match := pattern.search(data)) is not None:
# Do something with match
# A loop that can't be trivially rewritten using 2-arg iter()
while chunk := file.read(8192):
process(chunk)
# Reuse a value that's expensive to compute
[y := f(x), y**2, y**3]
# Share a subexpression between a comprehension filter clause and its output
filtered_data = [y for x in data if (y := f(x)) is not None]
# Compute partial sums in a list comprehension
values=[1,2,3,4,5]
total = 0
partial_sums = [total := total + v for v in values]
使用上有些限制
y:= f(x) # INVALID
(y := f(x)) # Valid, though not recommended
# there is no syntactic position where both are valid
foo(x = y := f(x)) # INVALID
foo(x=(y := f(x))) # Valid, though probably confusing
foo(x := 3, cat='vector')# Valid
# parsing keyword arguments is complex enough already
(lambda: x := 1) # INVALID
lambda: (x := 1) # Valid, but unlikely to be useful
(x := lambda: 1) # Valid
lambda line: (m := re.match(pattern, line)) and m.group(1) # Valid
# Unparenthesized assignment expressions are prohibited in lambda functions.
[i := i+1 for i in range(5)] # INVALID
# the for i part establishes that i is local to the comprehension
# but the i := part insists that i is not local to the comprehension.
字节码的实现
import dis
def f(x=0,y=0):
print(x,y)
def g():
f(x:=3)
print(dis.dis(g))
def h():
f(y=3)
print(dis.dis(h))
########################result##########################
51 0 RESUME 0
52 2 LOAD_GLOBAL 1 (NULL + f)
14 LOAD_CONST 1 (3)
16 COPY 1
18 STORE_FAST 0 (x)#x被作为本地变量保存了下来
20 PRECALL 1
24 CALL 1
34 POP_TOP
36 LOAD_CONST 0 (None)
38 RETURN_VALUE
None
56 0 RESUME 0
57 2 LOAD_GLOBAL 1 (NULL + f)
14 LOAD_CONST 1 (3)#直接是常量的传递
16 KW_NAMES 2
18 PRECALL 1
22 CALL 1
32 POP_TOP
34 LOAD_CONST 0 (None)
36 RETURN_VALUE
总结来说:就是能用 = 的时候,不支持用 := (虽然可以给赋值打上括号,使他不仅仅是赋值还是一个有返回值的表达式)
基本上打个括号作为能赋值的表达式使用不会错
参考:
- 《流畅的python》
- https://github.com/python/cpython
- https://peps.python.org/pep-0572/
如有错误,欢迎指出