python 拾遗(一)

本文介绍了Python中的PyVarObject底层结构,探讨了内置类型如何处理可变长度容器,并详细解释了`__getitem__`和`__len__`方法的行为。此外,还讨论了walrusoperator的新特性及其在代码中的使用实例,以及字节码实现中的注意事项。
摘要由CSDN通过智能技术生成

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/

如有错误,欢迎指出

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值