昨天我们简单的学习了数据结构并且写了一个小demo
坏蛋Dan:python简单入门--day3:数据结构和小例子
今天我们来了解下python
的面向对象编程理念、输入输出、错误的捕获处理、标准库以及其它
前面我们写代码都是基于函数,以一块语句的方式来修改数据,这种一般叫做面向过程编程(precedure-oriented programming
)。
而我们还以可以用另一种方式,将一系列函数等组合到一个对象里面,这种则是面向对象编程(object-oriented programming
)。
这两种编程理念都没问题,大部分时候我们都可以使用面向过程编程,而小部分时候不适合面向过程,那么就可以采用面向对象的方式。
类(classes
)和对象(objects
)是面向对象编程的两个主要方面。
类可以创建一个新类型,而对象是类的一个实例。
比如通过int
创建的整数变量都是对象,而int
是一个class
,所以这些变量都是int
这个class
的实例。
对于对象/类里面的变量来说,一般被叫做字段(fields
)。 也可以是函数,但是函数只可以定义于class
里面,不过作为类的实例,对象也可以使用这些函数。
字段有两个类型:
instance variables
class variables
和一般的函数对比,类里面的函数(一般用来区分叫做methods
)唯一的不同点就在于它的第一个参数必须要是self
(一般叫self
,你也可以自定义), 这个self
不需要我们传入,编译解析的时候会自动带上。(可以参考Rust
里的struct
implement
的methods
)。
至于为什么不需要我们手动传入self
,这里有个简单的例子用于理解:
比如我们有一个MyClass
的类和它的实例myobject
对象,当我们通过myobject
调用定义在MyClass
里的methods
的时候:myobject.methods(arg1, arg2)
,在编译解析的时候会被python
转换为MyClass.methods(myobject, arg1, arg2)
。所以我们并不需要手动传入。
定义类的关键字是class
,字段和函数都定义在这个类的block
里面。
直接来看下例子
创建类的实例不需要new
关键字
__main__.Person
:表示这个p
对象是当前module
里的Person
类的实例对象,而后面这一段十六进制则是我们这个对象在堆内存上的地址。
直接来看下例子
__init__
方法在类里面有一些特殊的methods
,而这个__init__
则是其中一个。
这个方法会在一个对象实例被创建的时候执行,相当于其它语言的constructor
。
我们来看下用法
前面说过,类和对象的变量叫做字段(fields
),并且字段有两种类型:instance variables
和class variables
。
顾名思义,就是类的字段和对象的字段。
Class variables
: 类字段是公用的(shared
),它们也可以被这个类的实例对象访问。不过需要注意的是,类字段是唯一的,如果存在多个实例对象,那么这些实例对象共用这个字段,当其中一个对象改变这个字段的时候,所有的类对象访问这个字段的时候也都会发生改变。Object variables
:这些字段由实例对象自行管理,即当数据发生变化的时候并不会影响到其它实例对象。我们来看下例子
这里的name
是对象字段,而population
这个字段则是一个类字段。
注意self
也是对象自身的,而不是类的。
另外我们还可以用self.__class__
这个attribute
去访问类字段:self.__class__.population
(类似前端的通过prototype
去访问)。
这里还有一个装饰器(decorator
[1]):@classmethod
指明how_many
这个方法是类私有的,实例对象不能访问。
简单地说,这里的装饰器算是一种语法糖,相当于以下写法
所有的类字段都是公用的,除了通过__
开头的,通过__
开头的比如__privatevar
指明这个字段是类私有的,创建的实例对象不会有这个字段。
继承是面向对象编程的其中一个特性,我们可以通过继承来复用一些方法。(一些语言比如go、rust
都不再实现这个特性,改用implement crate
等方式实现,因为继承是全部继承,存在浪费。)
比如教室,A教室和B教室,对于这两个教室来说,教室的所有属性比如教室的介绍、用途都是一样的,但是子类又需要有自己的属性,比如名字叫A或者名字叫B。
那么这个时候我们可以构造一个父类叫做:教室,把一些相同的特性都翻到这个父类里。然后实现两个子类A教室和B教室继承这个父类。
教程里给出的例子是学校的成员,有教师和学生,但他们无疑都是学校成员。
语法是在类定义类名的地方加上(需要继承的类,允许传入多个,需要用[]包裹)
这个写法有些类似于js
中的伪继承。
其它我就不必多说了,相信大家都清楚。
作为程序,和用户进行交互是不可避免的。那么交互就有两个点需要实现:输入和输出。
我们前面已经接触过相关的api
了,输入:内置的input
方法;输出:内置的print
方法。
我们直接来看下例子
一个简单判断字符串是否是回文的代码片段。
当然,交互可不止有输入框,文件操作也算是一种交互。
直接来看下如何简单的读/写一个文件,来个经典的例子
open
是内置的函数,第一个参数是path
,第二个参数是可以选的,默认是-r
表示read
读,当传入-w
的时候表示写(覆盖),-a
表示写但是非覆盖,在原有基础上新增。
另外还有两个mode
,-t
表示操作的是文本,而-b
则表示操作的是二进制(binary
)。
默认情况下是将文件视作-t
,打开则是-r
。
还有其它不太常用的,你可以直接通过help(open)
来查看其它的mode
。
python
标准库中提供了一个模块叫做pickle
,翻译过来就是腌制的意思,而它的用法也如它的名字一样。
它允许我们将任何原始的python
对象存储到文件中并在之后返回。
wb
表示write binary
,而rb
表示read binary
。
另外我们还可以指明encoding
,一般都是utf-8
当遇到程序错误的时候,python
中物理终端程序的方式是ctrl + z
(window
,Mac
上则是ctrl + d
)和传统的ctrl + c
是不同的,这一点需要注意。
处理物理手段之外,还有我们最常见的try catch
,但是在python
则是try except
,我们来看下例子
类似if ... elif...else
一样,可以存在多个条件。
有些错误是runtime
的时候才会触发的,这个时候一般兜底逻辑也不适用,这个时候就需要把捕获到的错误抛出,然后手动去跟踪排查问题最后处理。
这里就需要使用到raise
关键字
我们还实现了一个类:ShortInputException
,它继承于Exception
这个类。
另外我们还使用了as
这个关键字指明这个类捕获的错误变量名为ex
。
这个自然就不必多说了,直接来看下例子
with
语句这个语法需要特别留意,在python
中with
这个语句有特殊用法,我们先来看下例子
这个例子和我们之前写的open
的是差不多的,唯一的不同点在于我们并不需要手动的去写f.close()
,这个过程交给了with
语句块自动实现。
在进入到with
语句块的时候,它会去执行thefile.__enter__
这个函数,然后在这个块结束后执行thefile.__exit__
函数。
实现应该可以参考rust
中对于Drop
的implement
。
这个with
可以用来替代try...finally
,会优雅些。
一门编程语言一般可以拆分为三部分:
core
:核心代码,一些基础数据结构等。standard library
:标准库,对于core
的一些补充拓展,比如一些非常非常常用的api
实现,一般是内置的,也就是当你安装对应的语言环境的时候也会顺带带上,需要注意core
没有了标准库照样能活。third-party dependences
:第三方依赖,这种就不是自带的了,需要用户手动去install
。sys
是system
的缩写,是用来处理和操作系统相关的,我们之前使用过的sys.argv
方法就是。
sys.version_info
:这个方法是用来输出python
的版本的。这个模块一般是用来将内容存储到日志里的。
常用的标准库模块还有很多,比如debugging
[2]、handling command line options
[3]、regular expressions
[4]等。
可以跟着这个教程学习标准库模块:http://pymotw.com/2/contents.html
目前我们已经简单的接触和了解了基础的知识,这里做一些常见的内容补充。
如果你想一次返回多个不同类型的东西,那么这个时候你就可以使用元组
注意这里errnum, errstr = get_error_details()
,这里是用了解构。
另外这个还能做骚操作,比如快速的交换两个变量的值。
a, b = b, a
,等价于(a, b) = (8, 5)
。
注意,我这里说的是方法(methods
),而不是函数(functions
)。和rust
一样,methods
指的是关联的函数,而functions
则是普通函数,区别在于第一个参数是否是self
。
特殊指的是内置的。
我们之前就见过了两个类中的特殊方法:__init__
和__del__
。
除了它俩之外还有几个常见的:
__str__(self)
:当我们使用了print
函数或者str()
函数的时候就会触发这个methods
。__lt__(self, other)
:当<
操作符被调用的时候就会触发,同理于其它的操作符。不要觉得有些奇怪,因为python
中万物皆对象。__getitem__(self, key)
: 当x[key]
索引操作符被使用的时候触发。__len__(self)
:当len()
函数被用于sequence
的时候触发。简单地说这个lambda
就是用来创建新的函数的。
我们先来看下例子
它接收参数,也就是上面的i
,而i['y']
则是函数的表达式语句。
先来看下例子
这里表示查找大于二的元素,然后将它*2
处理。
有些不太好理解,但是确实是挺便利的。
assert
语句用来断言某个语句是否为true
,我们在rust
中写测试元的时候就很常用到。
前面说过,装饰器就是一种语法糖写法,它是函数包裹的简写。
类似宏(macro
),宏是操作与抽象语法树的,在编译阶段会被展开。
来看下例子
那么基础的东西我们就稍微的过了一遍了,python
的东西还是很好入门的,但是要真用于开发,我们目前的知识还是差了很多,所以后面还需要去找些项目入门。
发布于 2023-04-02 17:54・IP 属地广东