我的Python学习之路

写于2018,2024.6

本篇笔记用来记录我学习 Python 过程中的一些思考。

准备

一颗好奇心。

知识基础

最好有初中数学水平,最好能先知道 y=f(x)=x+1 这个式子的含义。

最好有初中英语水平,会一些简单的单词如 if, yes, no.

最好有些许想象力,如想象一个数字 1.

书或视频

想推荐的好书太多了,而且好的观点或思路往往分散在各个好作品里面,我只能尽可能推荐一些特别出色的(想起哪个随时添加):

视频:3Blue1Brown 把线性代数和微积分用图形直观地表达,给我很大启发。

安装 Python

官网:https://www.python.org

Python 学习之路

本文以 Python 这一OOP(Object O Pragrame, 面向对象编程)语言为例,探讨面向对象的编程思想。

哲学基础,计算机哲学,本体论,可计算性,数理逻辑。

世界本质为人感知到的表象。

一切的前提,假设表象世界实际存在,也就是说,假设表象世界即真实世界。

这就是程序员必要的思维方式,考虑周全。

也是数学家,理论物理学家的思维方式,假设+推理。

悬置这个问题,把这个问题交给其他学科。

本体,对象,object 顺便拓展到机器学习的agent(代理)

描述对象,属性

和机器(计算机)这个对象的交流

反观人类,你理解脑海里的那些神经元活动?

人类不知道一个文字,一段声音,通过一道道转化,编译,翻译之后,在意识里呈现(或链接到已有概念)的模样下,不妨碍人类能看和听

同理,机器人不需要理解底层的机器码,汇编码,C语言等编程语言

(把一台计算机整体当作一个对象

AI通过与世界的交互,产生智能是迟早的事

人类不断通过翻译,教会计算机越来越多)

1 抽象

什么是抽象?

观察者(可以是任何具有观察能力的对象,如人类)观察对象,再用简化的语言表达这个对象,这个过程就是抽象。

这世界上没有两片相同的树叶。

为了方便,我们取一个名字树叶来代表一切具备某些相同性质的所有树叶对象

由此可见这世界的复杂性。
简单规则的复杂呈现,称为混沌。

可以认为,这世界上所有对象都是独一无二的。

对象太多太繁杂了,为了简化,我们抽象出一些共性(共有特性,属性),以便给对象分类,减轻大脑计算和记忆负担。

计算成本,称为计算复杂度。记忆成本,称为空间复杂度。

简化的语言,可以是任何符号。

数学中,一般用 x, y 等符号代表一个数学对象。

编程中,一般用 object 代表一个对象。

object  英[ˈɒbdʒɪkt];美[ˈɑ:bdʒekt]
n. 物体; 目标; 宾语; 客体,对象;
vi. 不赞成,反对; 抱反感;
vt. 提出…作反对的理由;

现实世界中,我们用语言符号来代指一个对象。

这个语言符号(如某人的名字)可以看作是一种共识,约定。

例如,我们用苹果指代一种水果,又用水果指代一种植物,又用植物指代一种生物。。。

可以发现,我们取名时很依赖对象的类别,也就是说,更多时候,我们是在给对象的类别取名。

真正给对象取名时,那个名字往往具有很大局限性。

要看上下文环境。

给具体或抽象对象取名时,往往很简单一个昵称,短小的几个字就可以指代。

然而要传达稍稍精确些,便要不断添加描述,约束,上下文环境。

名字的上下文环境,编程中叫命名空间(name space)

特别地,在一些细分领域,有很多专业术语或缩写,放在普遍语境下会重名,产生歧义。

在编程中,为了应对这样的情况,出现了 DSL(Domain Specified Language)领域专用语言

抽象就是 给对象取名字 这一行为。

这个名字可以没有任何含义,单纯作为一个占位符参与一个计算或描述。

给对象取名字 变量

给有某种模式的变化取名字 函数

对,观察对象,的抽象,取名为x,称之为变量,写作 x

对,观察对象与外界交互这一过程的抽象,称之为函数,写作 f(x)

理想情况下,这样表述没有问题
实际情况下
观察者一旦观察,就会产生交互
所以,一切都是对象,都是交互的
不可交互对象可以认为它不存在

方程:

f(x)=x+1

f(x) 代表 x + 1

这个式子(不叫公式,也不叫方程,后面说明)描述 x 经过 f() 这个变化

有一个变化给它取名叫 f(),它表示x对象加上1

变化太 low 了,索性给它取个名字叫函数高大上一点。

再看下面:

y=x+1

这个方程描述对象 x 与对象 y 之间的一种关系。

可以发现,这样全部用等号表述,很模糊,容易混淆。

f(x)=x+1 本质上是:

f()x+1

把 对象加一 这个 变化 取个名字叫函数 f()

而 y=x+1 本质上是:

xfy(f(x)x+1)

这样就好多了。

函数,指代对象的变化。

方程,描述对象之间的一种关系。

函数,指代对象的一个交互方式。

在OOP(面向对象编程)中,我们用方法指代对象的交互,其实就是函数。

在 Python 中 :

x=x+1

表示

xx+1

给 x + 1 这种行为(或变化)取个名字叫 x

在其他编程语言中,往往称之为给变量 x 赋值 x + 1

等号在编程中的不同含义:

一般的编程语言中, = 相当于给左边的 变量(Varable) 赋右边的 值(Value) ,像是给左边的瓶子装右边的水。

Python 和数学里的代数思想中, = 相当于给右边的变量取个名字,放在等号左边。像是给右边的对象取个左边的名字。

我之所以喜欢 Python ,一个重要原因便是思维方式上更契合数学思想。

方程,相当于描述这种交互过程,描述对象之间的一种关系。

观察

想象一个完全静止的世界,里面所有对象都是静止的。

或者说,一个没有时间维度的世界,一个熵增到达极限,万物趋于静止的世界。

静止的世界中,任何对象都无法变化。

静止的世界,可以认为它不存在

不可观察的世界,可以认为它不存在

不论其他地方的存在不存在如何定义,我们这里可以先暂且这么认为。

在脑海(意识界)中的抽象对象,由于可以观察,我们可以认为它们存在。

说到观察,当然有一个观察者,一个观察对象,一个观察者的观察方法。

不管观察方法是什么(视觉,听觉,味觉,嗅觉,肤觉,感觉),我们姑且给这些方法统一取个名字称之为 观察

说到观察,最直观的方法就是视觉了,所以用视角来表示这种方法。

我们可以这样描述人观察一个对象的过程。

fgf()g()gg()gg()gg

视角

视角的不同,可以观察到不同层次的对象。

我们就以目前理论物理最新成果弦论和其他物理学成果为参考,来演示这种视角与层次的关系。

就从最抽象的地方开始吧

视角的自由度

自由穿梭于不同的观察层次

计算机科学,MIT教材与视频里描述的抽象

数学,《数学之旅》视频那个老师描述的抽象

对象

Object,物体,项目,东西,对象

我们把前面说到的东西用一个简单的方式表示:

在 Python 中,我们可以这样表示:

class observer(object):  
# 一个叫 观察者 的类,属于对象类  
    def __init__(self, observe)  
      
class human(observer):  
  
zhangyunlu = human()  

对象包含属性(数据,信息)与方法(交互,互动)
为什么?
属性,不也是对象与(观察者)交互产生的吗?
暂时再悬置这个问题。

具体编程时,遇到再说。

把python当作对象,来描述python里的对象

class proguaming_luanguage:  
pass  
  
python.pl():  
pass  

这世界上没有两片相同的树叶。

可见复杂性

简单规则的复杂呈现

可以假设:这世界上所有对象都是独一无二的。

那对象太多太繁杂了。为了简化,我们抽象出一些共性(共有特性,属性)

我们已经知道,函数代表一个对象的变化。

给对象分类。

即使世界上没有两片相同的树叶,我们也可以把树叶当作所有具有与(我们对树叶所描述的)类似模式的对象,给这类对象取名:

class leaves():

下面看这段话:

任何具体或抽象的事物,取个名字叫对象

如果,这些具有某些可识别的模式,可以把这些识别到的模式取个名字叫对象的属性

如果,这个对象与外界交互,那可以把这种交互取个名字叫函数(function,功能,函数)

可以看到,上面这段话有两个「如果」和三个「取个名字」。

换成编程语言,就是说这段代码有两个if和三个name

name是一种很方便的抽象(封装)方法,给任何一个对象name,就能节省下脑力(或计算空间资源等),把这个name当作一个函数和它交互。

if,我们知道if是条件分支,那是否有和以上if平行的其他分支呢?

1,第一个if,是否有不具有可识别模式的对象?

例如,某种不可知宇宙的一种不可知对象。

换言之,如果一个对象无法与人有任何交互,即无法被任何手段观察到,那这个对象是否存在?

再看另一个例子。

别人告诉你,某某地有某某事物。

如果他的话100%可信,那这个事物即对象存在否?

没有照片或其他记录显示该地有该物。

你可以认为,该对象很可能存在。

可能性问题。任何不能亲身感知的事物或事件,只能依靠信念fairy,原则principle,科学方法来做一个可能性的判断。

如果有一个不可感知(即互动)的对象,也就无从得知模式(数学是否可以reach不可知对象?)

这个问题,也就是if之外的else部分,留给哲学家,数学家,理论物理学家们去探索吧。

2,第二个if,是否存在不可交互的对象。

区分属性与方法:object.attribute  object.method()

属性可以看作变量,方法可以看作函数

x=1
f(x)=x+1
y=f(x)=2

一个函数可以给它取个名字,可以看作一个变量

「变量」只是一个称呼,一个名字,一个占位符。可以给任何对象,或这个对象内部的任何对象赋予变量之名。

在 Python 中:

def function(parameter)  
    parameter = (input())  
    return parameter + 1  
# 定义一个函数,内含参数  
# parameter 和 argument 都是参数的意思  
# 我就取 parameter 作为代指参数吧  

parameter, 参数,参变量,也就是变量。

可以看到,这在数学中相当于:

定义一个函数 y = f(x)

x = N 你随便取一个整数

我把 x + 1 (使用函数作为方法操作,变化之后)

返回结果

是的,它看上去没有直接说明:

f(x)=x+1

而是在返回时才把参数变化:return x + 1

这就是封装思想:

只要定义了一个函数,取个一眼就大概能知道意思的好名字,我们就不需要知道它内部的细节,而可以把它当做一个模块直接调用。

一个变量能看作函数吗?

y=x+1y=f(x)f(x)=y=2x=1

事实上

y=x+1

这个式子,描述了一种对应关系,x=多少时,y=多少。

把这种两个对象之间的互动(关系,变化,映射,依赖。。)抽象出来,也就是说给这种看不见的联系取一个名字,叫函数(编程时叫方法)。

在数学中,任何函数,都可以看作是对某种数学对象的一种变化操作

高等数学,特别是线性代数与编程之间关系密切

理解了数学,对函数与变量的理解也就更为清晰。

一个变量,与一个函数之间有什么关系?

两个集合,其中一个集合的变量通过映射(函数),得到另一个变量。

(风动,云动,心动?)

类,一个集合,包含了一群对象

属性,对象的描述

方法,对象内部函数,与对象的互动接口

函数,变量(占位符),映射

高阶函数,变量为函数的函数

1.3 类

给有某种模式的对象集合取名字 类型

这世界上很多对象之间有相同或相似的地方,为了方便,把这些具有某些共同模式的信息的对象之上,再抽象出来并取一个名字,叫类。

同类的对象,可以共享一些互动方法。

这样可以进一步节省对象的信息(空间)资源。

类下面还有子类,派生类,以后碰到再说。

约定: 类(class)名一般以大写开头

自指

看看这样一个函数

an+1=an+1

函数

现实世界,万物随着时间而变化。

把时间当作自变量,万物当作因变量,这就形成了一个自变量与因变量之间的对应关系。可以称之为函数。

y=f(x)=x+1

给这个函数取个名字 y

y 与 x 之间有某种对应关系

an+1=1.02an

函数一般我们会取个名字f(), 代指这种变化。

Python中,有一种特殊的函数表达方法:lambda

lambda 匿名函数
# -*- coding:utf-8 -*-  
  
# 普通函数  
def function(a,b,c):  
    return a+b+c  
  
print function(1,2,3)  
# 返回值为 6  
  
# lambda 匿名函数  
f = lambda a, b, c : a+b+c  
  
print f(1,2,3)  
# 返回值为 6  
  

可以看到,相比普通函数要多一行代码来定义,lambda 匿名函数可以不用事先声明而直接创建表达式。

普通函数需要使用def 这个方法,定义(声明,赋值,命名)一个函数,通过输入参数并返回值的方式来运算。

也就相当于,把这个运算过程封装(打包)成了一个代码块。

而且,运算之前必须先定义这个函数。

如果这个函数本身非常简单,感觉没必要专门给他一个名字时,就可以使用 lambda 匿名函数,随用随走,用完就扔掉。

我们知道,一个函数如果没有名字,那 Python 如何能找到它在内存中表示变化的代码块呢?

所以,lambda 表达式的意思大概是:lambda 后面跟着的就是一个函数,直接把这个函数打包叫做lambda 参与运算。

这样就可以节省时间,不需要为了一点小函数去大动干戈 def 一个。

多种编程语言对比

C:

include stdio.h /导入标准函数库  
include math.h /导入数学函数库  
  
int main  
  

  
return 0  

Java:

  

Python:

# Python不需要导入print和一些基本数学运算的函数,本身自带这些内置(init)函数。  
# 具体编程时,一般开头是这种格式: import xxx 用以导入模块(即C语言里的库)  
  
a = 1 * 2 # Python声明变量不需要var,main  
print (a) #是的,只需要两句。。  
  
  

最近又看上了 JavaScript 小姑娘(据说和Java没有血缘关系)。。

JavaScript:

声明  
  
var a = 1 * 2  
  

在JavaScript中:

function show(x)  
    {  
        console.log(typeof x);    // undefined  
        console.log(typeof 10);  // number  
        console.log(typeof 'abc'); // string  
        console.log(typeof true);  // boolean  
  
        console.log(typeof function () {});  //function  
  
        console.log(typeof [1, 'a', true]);  //object  
        console.log(typeof { a: 10, b: 20 });  //object  
        console.log(typeof null);  //object  
        console.log(typeof new Number(10));  //object  
    }  
show();  
  

可以看到,在JavaScript中

- undefined
- number
- string
- boolean

以上四种对象属于类型,不属于 object type(对象类型)

- function
- array 数组
- object
- null
- new Number(10) 实例

以上皆是引用类型,都是object type

判断一个变量(name)是不是对象:

- 值类型
  typeof

- 引用类型
  instanceof

var fn = function(){};  
console.log(fn instanceof Object); //true  

不同编程语言的对象区别

C# / Java / Python

new class 创建一个类的实例

对象内部必须要有:

- 字段

- 属性

- 方法

JavaScript / Python

Python中只需要有属性和方法,而方法实际上操作上和属性一样,也就是说Python和JavaScript一样——方法也是一种属性——方法的的形式为键值对(key-value)。

另外,在Python中,键值对是dict(字典)的元素特性。

Python 创建对象:

Object = Class() # Python创建一个Object对象  

JavaScript 创建对象:

var obj = {  
    a: 10;  
    b: function(arg){  
        alert(this.a + x);  
    },  
    c:{  
        name: '张三';  
        year: 1990;  
    }  
}  

一般我们会把对象内部的变量(varriable)称为属性(attribution),函数(function)称为方法(method)

而本质上,一个对象内部的函数,也是它的属性,只是这个属性与其他属性稍有区别罢了。