月初在图书馆借阅了《自学是门手艺》、《数据结构与算法·python语言实现》,断断续续看了四天多,今天开始正式撰写编程练习笔记,目前的最高目标就是把书本上的文字理解透,用自己的话表达出来。
基础篇
文章痕迹
学习计划
2024-1-21
学习了数据类型、分支循环
2024-1-28
- 类的学习
- 完善数据类型
2024-1-31
增加目录,完善变量与数据类型
函数调用
python是一种面向对象[1]的编程语言,有些特性与java很相似,其中一个极其相似的特征就是函数调用的语法。
Python可以通过使用的.
(点操作符)来调用函数。例如我们现在有一堆数据(data
)要进行排序(sort
),我们便可以通过data.sort()
来实现,其中点左侧的是被操作的对象,相当于自变量,右侧即所使用的方法,相当于函数。
另外不值得注意的一些废话是:
- 有些方法仅仅会返回对象的状态,例如数量、数据类型、最值、平均值、平方差等,并不改变其状态
- 有些方法则会改变对象的状态,例如重新排序,更改大小写等等。
变量的命名规则
- 变量名只能包含字母、数字和下划线。
- 不能以数字开头
- 不能与Python中关键字和函数名相同
- 不能超过79个字符
潜规则:如果标识符名称以单个下划线开头,表示它是私有的,双下划线开头表示它是强私有的。
内存管理
栈:用来存储对象(如变量名等)用id来标识堆:用来存储对象的值。
特点:栈中值相同的对象会指向一个堆;栈的对象一旦调用结束(比如在一个函数运行过程中使用的中间变量)就会被移出栈,相应的在堆中储存的某些中间值也会被清空,从而来释放内存,仅将目标堆栈保存。
那么如何认为判定该对象是中间变量或者已经没用了?Python采用了引用计数的方法:当一个对象被其他对象引用时,就会增加一个计数,不被引用时,就会减少一个计数,当其计数减小到零时,就会判定它已经没用了,下一波垃圾回收到来时,就会被抹除掉。
比如给一个值为666
变量A
赋值为999
,那么原本存储666
的内存就会失去引用,就会被回收。可以通过身份运算符来验证两个对象是否存在于内存的同一个部分:
is
:如果两个操作数相同,则返回True
is not
:如果两个操作数不相同,则返回True
1 | Before = 2077 |
数据类型
字符串
类型 | 语法 | 例子 | 特点 |
---|---|---|---|
字符串 | 'string' 、"string" 、"""跨行字符串""" |
'bulabulabula' | 一系列字符 |
关于字符串的罗马文本处理,有以下几个常用函数:
title()
:单词首字母大写upper()
:全部改大写lower()
:全部改小写f"{}"
:将花括号内的变量替换为其值rstrip()
:删除字符末尾的空白
1 | Song = 'viva la vida' |
数
类型 | 语法 | 例子 | 特点 |
---|---|---|---|
字符串 | number |
666 |
一个整数 |
数据类型格式转换
先介绍下format()
函数,用来替换字符串中的某些值。也是一个与中\newcommand
命令极为相似的一个函数:
1 | \newcommand{\youname}[2]{我是:#1 #2} % 定义带两个参数的命令 |
1 | print("我是{0}{1}".format("秉","蕑")) |
列表
索引
类的试验
1 | #!/usr/bin/env python3 |
1 | year的布尔值为: True |
(假想)分数型
关于数据类型,主流的高级语言都有整型、浮点型、字符型、布尔型四大类,然而我们都知道,在计算的时候,约分为小数是有误差的,不管再怎么把浮点的精度提高,也无法保证绝对的精确,那么为何没有一种分式的数据类型呢?
我们就可以假想一个分数型数据,姑且用两个点来区分分子分母,比如用1..3
表示 ,这样一来可以把它看作占用来两个整型数据的空间。当计算数据的时候,就跟浮点与整数运算后变浮点一样,一旦有一个分数型数据参与计算,就需要整型变为k..1
,浮点变为abcd...1000
,全程使用分数进行运算。如有必要显示数值,则在将分数转化为易读的浮点类型或整数型。分数型的核心不可避免的是通分与约分,这种提高精度的方法势必会增加计算复杂度,虽然简单的加减法都需要通分一下,但涉及到乘除运算的时候,效率有时候还是蛮高的。
当未来某一时期,算力变得廉价时,这种牺牲步数而追求更高精度的方法也会被大量使用吧。
运算符
python的运算符非常口语化。比如:
与或非就是and or not
,等价就是is
,不等就是is not
;元素在序列中:in
,不在序列中:not in
。
算术运算符中整式除法//
与取模%
运算很有意思,前者要满足得出的值为不大于商的最大整数(所以
自加运算与赋值相加是有略微的区别的。
分支与循环
据说利用分支和循环可以解决任意复杂度的流程控制,下面咱们来试试:
if语句
1 | import random |
While语句与for语句
if语句一般有两种思路来使用for循环,基于索引(是否包含),基于迭代(等差数列)。没啥好说的,直接来个练习:
1 | #!/usr/bin/env python3 |
函数
在python中,通过def
来定义函数,参数的数量在后面给出,不需要向tex一样命名参数的数量,比如我们定义一个名为count
函数来计算某个数据出现的次数。
1 | stuff = ['star', 'money', 'star', 'money', 'money', 'money', 'star', 'money',] |
函数可以看作一个简单的盒子,一边输入,一边输出。在上个例子中,定义了count()
函数,其输入为data
、target
,输出为n
。当执行到return
语句时,函数就会结束执行,并返回输出值n
。如果没有定义输出,就会返回一个None
。
疑问:没有输出的函数,意义何在呢?
疑问:自定义函数如何返回多个输出值?
疑问:为何有的函数括号里边儿是输入值,有的函数只在外边儿加个点儿就行了
类
类很像函数,但更为基础底层,是面向对象语言的特色。类中可以定义自己的函数,但是不叫做函数,而叫做方法,语法跟函数相比,只是在函数名前后添加了两对下划线:__count__
在_《Python编程:从入门到实践(第2版)》_中有这样一个例子:
1 | class Dog: |
我们将方法
__init__()
定义成包含三个形参:self
、name
和age
。在这个方法的定义中,形参self
必不可少,而且必须位于其他形参的前面。为何必须在方法定义中包含形参self
呢?因为Python调用这个方法来创建Dog
实例时,将自动传入实参self
。每个与实例相关联的方法调用都自动传递实参self
,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
面向对象的特点就是如此,先定义一个对象,然后赋予其各种属性。
类的特点
- self是一个特别的参数,不传递任何值,相当于C语言中的指针;即使有一个函数不带参数,仍然需要在函数定义中提到self。
- 类变量的特性:属于类本身,由类中的所有实例共享
继承
子类可以继承父类的特性,我们先创建一个父类
1 | class post() |
算法篇
大O符号
什么是面向对象,我也不清楚啦 ↩︎