#663 Python 内置函数: hash

2021-10-01

一个不值一提的小问题:
有个地方使用 hash 方法来做哈希计算,将字符串转换成一个数值,但是发现改用 Python 3 之后,这个值每次运行都不一样了。

#660 DedeCMS 开始割韭菜了

2021-09-29

织梦官网放出上面这张公告:除了 “个人非盈利” 网站,其他没有拿到正式授权的织梦网站需要交 5800 授权费。

他们可能已经把清单列好了,律师团队也准备好了,正磨刀霍霍向着小站长们。

这可能就是中国特色开源协议的正确使用方式。

PS: 虽然我觉得 织梦CMS 是个垃圾,但我也不知道为啥,据说很多小站都是用的这个系统。

#658 Python 源码学习 11: PyFrameObject

2021-09-25
// Include/cpython/frameobject.h
struct _frame {
    PyObject_VAR_HEAD
    struct _frame *f_back;      /* previous frame, or NULL */
    PyCodeObject *f_code;       /* code segment */
    PyObject *f_builtins;       /* builtin symbol table (PyDictObject) */
    PyObject *f_globals;        /* global symbol table (PyDictObject) */
    PyObject *f_locals;         /* local symbol table (any mapping) */
    PyObject **f_valuestack;    /* points after the last local */
    /* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
       Frame evaluation usually NULLs it, but a frame that yields sets it
       to the current stack top. */
    PyObject **f_stacktop;
    PyObject *f_trace;          /* Trace function */
    char f_trace_lines;         /* Emit per-line trace events? */
    char f_trace_opcodes;       /* Emit per-opcode trace events? */

    /* Borrowed reference to a generator, or NULL */
    PyObject *f_gen;

    int f_lasti;                /* Last instruction if called */
    /* Call PyFrame_GetLineNumber() instead of reading this field
       directly.  As of 2.3 f_lineno is only valid when tracing is
       active (i.e. when f_trace is set).  At other times we use
       PyCode_Addr2Line to calculate the line from the current
       bytecode index. */
    int f_lineno;               /* Current line number */
    int f_iblock;               /* index in f_blockstack */
    char f_executing;           /* whether the frame is still executing */
    PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
    PyObject *f_localsplus[1];  /* locals+stack, dynamically sized */
};

// Include/pyframe.h
typedef struct _frame PyFrameObject;

字节码

def sum(a, b):
    return a + b

def test():
    print('hello world')
    print(sum(1, 2))

import dis
dis.dis(sum)
dis.dis(test)
2           0 LOAD_FAST                0 (a)
            2 LOAD_FAST                1 (b)
            4 BINARY_ADD
            6 RETURN_VALUE
5           0 LOAD_GLOBAL              0 (print)
            2 LOAD_CONST               1 ('hello world')
            4 CALL_FUNCTION            1
            6 POP_TOP

6           8 LOAD_GLOBAL              0 (print)
           10 LOAD_GLOBAL              1 (sum)
           12 LOAD_CONST               2 (1)
           14 LOAD_CONST               3 (2)
           16 CALL_FUNCTION            2
           18 CALL_FUNCTION            1
           20 POP_TOP
           22 LOAD_CONST               0 (None)
           24 RETURN_VALUE

行号,指令偏移,指令,参数,参数值(参考)

查看字节码:

sum.__code__.co_code
sum.__code__.co_varnames
sum.__code__.co_consts
sum.__code__.co_names

参考资料与拓展阅读

#657 孟晚舟回国

2021-09-25
  1. 孟晚舟 1972 年出生,今年 49 岁。
    PS:任正非 1944 年出生,今年 77 岁,28 岁时生的孟晚舟。
  2. 2018 年 12 月 1 日,华为创始人任正非长女,也是华为的 CFO,孟晚舟(46 岁)在加拿大温哥华转机的时候,被加拿大警方逮捕。事后公布的原因是应美国政府要求引渡孟晚舟。时值中美贸易战,我不懂法律,美国起诉孟晚舟和华为的理由我是不清楚,目的肯定是打击中国科技企业。
  3. 2018 年 12 月 11 日,孟晚舟保释。看到网上公布的照片,孟晚舟一直戴着一个电子脚镣。
  4. 之后长达两年半的司法程序,直到今天结束,总共历时 1028 天。

看网络上的新闻,北京时间今天凌晨,孟晚舟和美国司法部达成了什么协议,孟晚舟承认了美国政府的部分事实陈述,但是不认罪,以此为代价,美国司法部结束引渡程序,并且只要孟晚舟在 2022 年之前,年前不再触犯美国联邦刑法,其将免于美国政府的起诉。加拿大随即释放孟晚舟,允许其自由离境。
虽然会被人质疑是 “人质外交”,中国政府还是释放了两名因涉嫌间谍罪而被逮捕的加拿大人(PS: 孟晚舟事件之后被逮捕)。

我不懂新闻中提到的那些个美国法律术语,只觉得折腾这么长时间,折腾了个寂寞,到了也没有怎么样,高高拿起,轻轻放下,就这样轻描淡写的结束了。
我的理解是,这件事情的发起是由于中美贸易战,结束则是由于美国放弃了和中国 “大决战” 的策略,拜登政府不想和中国硬钢。因为司法程序已经走到这一步,再沿原来的方向走下去就是彻底撕破脸了。

#655 URI

2021-09-24

URI 与 URL

                    hierarchical part
        ┌───────────────────┴─────────────────────┐
                    authority               path
        ┌───────────────┴───────────────┐┌───┴────┐
  abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
  └┬┘   └───────┬───────┘ └────┬────┘ └┬┘           └─────────┬─────────┘ └──┬──┘
scheme  user information     host     port                  query         fragment

  urn:example:mammal:monotreme:echidna
  └┬┘ └──────────────┬───────────────┘
scheme              path

URI

URI (统一资源标识符),标识一个资源主要有两种方法,根据名称(URN),根据路径(URL)。

URI 语法:

URL Syntax

有一个问题就是注册的 URI scheme 基本上都可以认为是用于资源定位,所以 URI 和 URL 的概念就比较模糊了。

有的 scheme,比如说 data:<mediatype>[;base64],<data>,既不算 URL,也不算 URI。
有的 scheme,比如说 sms:<phone number>?<action>,我觉得是属于名称标识,但是不符合 URN 的定义(必须 urn:)。

而且实际上,就比如说 URL http://example.com/user/create,我们用来创建一个用户,如果套用万维网创建时的学院派设想,我们只能把创建这个动作理解成一个资源了。所以,我认为深入讨论这几个 “统一资源” 的概念之间到底存在什么差异没有什么意义,大致知道他们的渊源就够了:先随着 WWW 出来了 URL 的概念,然后又有人整出来一个 URN,再后来统一为 URI 标准,这几个概念本来就是混乱的,这就是现实生活,泾渭分明的概念只存在于那些教授们的理想中。
如果感兴趣可以参考 RFC 3305,这是一个 Infomational RFC,就是试图解释这几个概念,并向社区作出使用建议。

URL

URL (统一资源定位符) = 协议://认证信息@主机名:端口号/路径?查询字符串#片段

协议必须是在 IANA 注册的合法 URI scheme。

我们最熟悉的是 HTTP URL,协议是 http 或者 https,除此之外还有其他的 IANA 批准的协议,比如:

  • mailto:<address>[?<header1>=<value1>[&<header2>=<value2>]]
  • imap://[<user>[;AUTH=<type>]@]<host>[:<port>]/<command>
  • git://github.com/user/project-name.git
  • file://[host]/path or file:[//host]/path
  • view-source:<absolute-URI>

URN

URN (统一资源名称) is 资源名称(唯一标识),格式:urn:<NID>:<NSS>

  1. urn 就是 IANA 注册的众多 URI scheme 之一。
  2. 这个命名空间标识 NID 也需要在 IANA 注册。

  3. urn:isbn:0451450523

  4. urn:ietf:rfc:2648

实际上,我好像没有见过什么地方在使用 URN,更别提设想中的统一资源属性 URC 了。

就好比上面提到的两个例子,ISBN: 0451450523,RFC 2648,直接这么写就是了,按照 RFC 定义写成标准的那一串实在是没见过。

总结

URL 是 URI 中的因特网部分,用来指示网络资源位置。

Python 示例

import urllib.parse

a = urllib.parse.urlunparse('http', 'user:pass@example.com:8080', '/path', 'param1=a', 'a=1&b=2', 'Title')
# 'http://user:pass@example.com:8080/path;param1=a?a=1&b=2#Title'

b = urllib.parse.urlparse(a)
b.scheme    # 0 'http'
b.netloc    # 1 'user:pass@example.com:8080'
b.path      # 2 '/path'
b.params    # 3 'param1=a'
b.query     # 4 'a=1&b=2'
b.fragment  # 5 'Title'
b.username  #   'user'
b.password  #   'pass'
b.hostname  #   'example.com'
b.port      #   8080

print(b[2]) # '/path'

b = urllib.parse.urlparse(('pymysql+mysql://root:111111@1.1.1.1:3306/xiaorui_master?charset=utf8mb4'))
print(repr((b.scheme, b.netloc, b.path, b.params, b.query, b.fragment, b.username, b.password, b.hostname, b.port)))
('pymysql+mysql', 'root:111111@1.1.1.1:3306', '/xiaorui_master', '', 'charset=utf8mb4', '', 'root', '111111', '1.1.1.1', 3306)

参考资料与拓展阅读