我的Python学习之路
写于2018,2024.6
本篇笔记用来记录我学习 Python 过程中的一些思考。
准备
一颗好奇心。
知识基础
最好有初中数学水平,最好能先知道 y=f(x)=x+1 这个式子的含义。
最好有初中英语水平,会一些简单的单词如 if, yes, no.
最好有些许想象力,如想象一个数字 1.
书或视频
想推荐的好书太多了,而且好的观点或思路往往分散在各个好作品里面,我只能尽可能推荐一些特别出色的(想起哪个随时添加):
视频:3Blue1Brown 把线性代数和微积分用图形直观地表达,给我很大启发。
安装 Python
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
这个式子(不叫公式,也不叫方程,后面说明)描述 x 经过 f() 这个变化。
有一个变化给它取名叫 f(),它表示x对象加上1
变化太 low 了,索性给它取个名字叫函数高大上一点。
再看下面:
这个方程描述对象 x 与对象 y 之间的一种关系。
可以发现,这样全部用等号表述,很模糊,容易混淆。
f(x)=x+1 本质上是:
把 对象加一 这个 变化 取个名字叫函数 f()
而 y=x+1 本质上是:
这样就好多了。
函数,指代对象的变化。
方程,描述对象之间的一种关系。
函数,指代对象的一个交互方式。
在OOP(面向对象编程)中,我们用方法指代对象的交互,其实就是函数。
在 Python 中 :
表示
给 x + 1 这种行为(或变化)取个名字叫 x
在其他编程语言中,往往称之为给变量 x 赋值 x + 1
等号在编程中的不同含义:
一般的编程语言中, = 相当于给左边的 变量(Varable) 赋右边的 值(Value) ,像是给左边的瓶子装右边的水。
Python 和数学里的代数思想中, = 相当于给右边的变量取个名字,放在等号左边。像是给右边的对象取个左边的名字。
我之所以喜欢 Python ,一个重要原因便是思维方式上更契合数学思想。
方程,相当于描述这种交互过程,描述对象之间的一种关系。
观察
想象一个完全静止的世界,里面所有对象都是静止的。
或者说,一个没有时间维度的世界,一个熵增到达极限,万物趋于静止的世界。
静止的世界中,任何对象都无法变化。
静止的世界,可以认为它不存在。
不可观察的世界,可以认为它不存在。
不论其他地方的存在
或不存在
如何定义,我们这里可以先暂且这么认为。
在脑海(意识界)中的抽象对象,由于可以观察,我们可以认为它们存在。
说到观察,当然有一个观察者,一个观察对象,一个观察者的观察方法。
不管观察方法是什么(视觉,听觉,味觉,嗅觉,肤觉,感觉),我们姑且给这些方法统一取个名字称之为 观察。
说到观察,最直观的方法就是视觉了,所以用视角来表示这种方法。
我们可以这样描述人观察一个对象的过程。
视角
视角的不同,可以观察到不同层次的对象。
我们就以目前理论物理最新成果弦论和其他物理学成果为参考,来演示这种视角与层次的关系。
就从最抽象的地方开始吧
视角的自由度
自由穿梭于不同的观察层次
计算机科学,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 (使用函数作为方法操作,变化之后)
返回结果
是的,它看上去没有直接说明:
而是在返回时才把参数变化:return x + 1
这就是封装思想:
只要定义了一个函数,取个一眼就大概能知道意思的好名字,我们就不需要知道它内部的细节,而可以把它当做一个模块直接调用。
一个变量能看作函数吗?
事实上
这个式子,描述了一种对应关系,x=多少时,y=多少。
把这种两个对象之间的互动(关系,变化,映射,依赖。。)抽象出来,也就是说给这种看不见的联系取一个名字,叫函数(编程时叫方法)。
在数学中,任何函数,都可以看作是对某种数学对象的一种变化操作
高等数学,特别是线性代数与编程之间关系密切
理解了数学,对函数与变量的理解也就更为清晰。
一个变量,与一个函数之间有什么关系?
两个集合,其中一个集合的变量通过映射(函数),得到另一个变量。
(风动,云动,心动?)
类,一个集合,包含了一群对象
属性,对象的描述
方法,对象内部函数,与对象的互动接口
函数,变量(占位符),映射
高阶函数,变量为函数的函数
1.3 类
给有某种模式的对象集合取名字 类型
这世界上很多对象之间有相同或相似的地方,为了方便,把这些具有某些共同模式的信息的对象之上,再抽象出来并取一个名字,叫类。
同类的对象,可以共享一些互动方法。
这样可以进一步节省对象的信息(空间)资源。
类下面还有子类,派生类,以后碰到再说。
约定: 类(class)名一般以大写开头
自指
看看这样一个函数
函数
现实世界,万物随着时间而变化。
把时间当作自变量,万物当作因变量,这就形成了一个自变量与因变量之间的对应关系。可以称之为函数。
给这个函数取个名字 y
y 与 x 之间有某种对应关系
函数一般我们会取个名字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)
而本质上,一个对象内部的函数,也是它的属性,只是这个属性与其他属性稍有区别罢了。