廖雪峰Python教程学习笔记(5)

Hazel ·
更新时间:2024-09-20
· 704 次阅读

目录8. 模块8.1 使用模块8.2 安装第三方模块9. 面向对象编程9.1 类和实例9.2 访问限制9.3 继承和多态9.4 获取对象信息9.5 实例属性和类属性 8. 模块

在 Python 中,一个 .py 文件就称之为一个模块(Module)。

模块是一组Python代码的集合,可以使用其他模块,也可以被其他模块所使用。

模块命名不要和系统模块名冲突,在 Python 交互式环境中,import abc,若成功说明存在此名称的系统模块;否则,不存在。

8.1 使用模块

sys模块是 Python 内置的一个模块。

使用 sys 模块的第一步,就是导入该模块:

import sys

导入 sys 模块后,就有了 sys 变量指向该模块,这样通过 sys 变量,就可以访问 sys 模块的所有功能。

作用域

正常的函数和变量名是公开的(public),可以被直接引用,比如 abc, PI等;

类似__xxx__ 这样的变量是特殊变量,可以被直接引用,但是有特殊的用途,比如 __author____name__ 就是特殊变量,自己一般不要这样命名;

类似_xxx__xxx 这样的函数或变量就是非公开的(private),不应该被直接引用,如 _abc, __abc 等。

_xxx 这样的函数或变量是可以被外界访问到的。但是,按照约定俗成的规定,这样的函数或变量表示的含义是“虽然我可以被访问,但是请把我视为私有变量,不要随意访问”。

8.2 安装第三方模块

在 Python 中,安装第三方模块,是通过包管理工具 pip 完成的。

第三方库,必须先知道该库的名称,可以在官网或者pypi上搜索。
比如安装 Pillow,命令是:

pip install Pillow

安装常用模块

使用Anaconda,这是一个基于Python的数据处理和科学计算平台,它已经内置了许多非常有用的第三方库。Anaconda 自带 Python。

9. 面向对象编程

在 Python 中,所有数据类型都可以视为对象,也可以自定义对象。

9.1 类和实例

在 Python 中,通过 class 关键字来定义类,如 Student 类:

class Student(object): pass

class 关键字后面跟着的 Student 是类名,类名通常以大写字母开头,这点和 Java 是一致的。

紧接着类名的是(object),表示该类是从哪个类继承下来的。通常,如果没有合适的继承类,就用 object类。object类是所有类最终都会继承的类。

pass 是空语句,一般用作占位语句,是为了保证程序结构的完整性。如果不加的话,会抛出异常:IndentationError: expected an indented block。之前的笔记里提到过。这里算是复习了。

使用 Student类创建实例:

bart = Student() print(bart) # print(Student) #

从打印信息可以看出,bart 指向的是一个 Student 的实例,它有内存地址;而Student 本身是一个类。

可以自由地给一个实例绑定属性

这一点真的很新鲜,它是怎么做到的?

bart.name = 'Bart Smith' print(bart.name) # Bart Smith bart.age = 32 print(bart.age) # 32 bart.salary = 20000.0 print(bart.salary) # 20000.0

把必须绑定的属性强制写进去

class Student(object): def __init__(self, name, score): self.name = name self.score = score

__init__ 方法的作用:通过一个特殊的 __init__ 方法,在创建实例的时候把 namescore等属性绑定上去。

__init__是一个特殊的方法,它的第一个参数永远是 self,表示创建的实例本身。

__init__ 方法内部,把各种属性绑定到 self

使用 Student 类创建实例:

# bart = Student() # 报错:TypeError: __init__() missing 2 required positional arguments: 'name' and 'score' bart = Student('Bart Smith', 0) print(bart) # print('name = %s, score = %s' % (bart.name, bart.score)) # name = Bart Smith, score = 0

注意到现在使用 Student() 这种方式直接报错,这是因为我们在类中使用了 __init__ 方法,就不能再传入空参数了,必须传入与 __init__相匹配的参数,但 self 是个例外,我们不需要传 self,Python 解释器会自己把实例变量 self 传进去。因此,需要传入的是 namescore

普通函数和类中定义的函数有什么区别?

区别只有一个,就是在类中定义的函数,它的第一个参数永远是实例变量 self,而且,在调用时,不用传递该参数。

数据封装

在类中定义方法,通过在实例上调用方法,就可以直接操作对象内部的数据,不需要知道方法内部的实现细节。

class Student(object): def __init__(self, name, score): self.name = name self.score = score # 定义一个类的方法 def print_score(self): print('%s: %s' % (self.name, self.score)) def get_grade(self): if self.score >= 90: return 'A' elif self.score >= 60: return 'B' else: return 'C' # 使用 Student 类 bart = Student('Peter Wang', 59) bart.print_score() # 打印结果:Peter Wang: 59 print(bart.get_grade()) # C

特别注意的一点

和静态语言不同,Python 允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称可能不同。

class Student(object): def __init__(self, name, score): self.name = name self.score = score # 对不同的实例变量绑定不同的数据 wang = Student('zhichao', 100) li = Student('xiaolong', 100) wang.age = 18 li.height = 176 print(wang.age) # 打印:18 # print(li.age) # 此行报错 ''' Traceback (most recent call last): File "student4.py", line 12, in print(li.age) AttributeError: 'Student' object has no attribute 'age' ''' print(li.height) # 打印:176 # print(wang.height) # 此行报错 ''' Traceback (most recent call last): File "student4.py", line 20, in print(wang.height) AttributeError: 'Student' object has no attribute 'height' ''' 9.2 访问限制

隐藏变量,对外暴露 getter/setter 方法

# 增加对属性的访问限制, 暴露出访问属性的方法 class Student(object): def __init__(self, name, score): self.__name = name self.__score = score def print_score(self): print('%s: %s' % (self.__name, self.__score)) # getter/setter 方法 def get_name(self): return self.__name def set_name(self, name): self.__name = name def get_score(self): return self.__score def set_score(self, score): if score >= 0 and score <= 100: self.__score = score else: raise ValueError('illegal score') wang = Student('zhichao', 100) # print(wang.__name) # 此行报错 ''' Traceback (most recent call last): File "student6_access.py", line 12, in print(wang.__name) AttributeError: 'Student' object has no attribute '__name' ''' print('%s: %s' % (wang.get_name(), wang.get_score())) # 打印:zhichao: 100 wang.set_name('zhijie') # wang.set_score(150) # 不合法的分数,抛异常 wang.set_score(99) print('%s: %d' % (wang.get_name(), wang.get_score())) # 打印:zhijie: 99 9.3 继承和多态

继承

class Animal(object): def run(self): print('Animal is running...') class Dog(Animal): pass class Cat(Animal): pass dog = Dog() dog.run() # 打印:Animal is running... cat = Cat() cat.run() # 打印: Animal is running...

上面的代码里,Dog 类 继承了 Animal 类,写法是把 Animal 写在 Dog 后面的圆括号里面。这时,我们说 Dog 类是 Animal 类的子类,Animal 类是 Dog 类的基类、父类或超类。

通过继承,子类获取了父类的全部功能。

子类还可以增加一些方法。

多态

# 多态 class Animal(object): def run(self): print('Animal is running...') class Dog(Animal): def run(self): print('Dog is running...') class Cat(Animal): def run(self): print('Cat is running...') def run_twice(animal): animal.run() animal.run() run_twice(Animal()) run_twice(Dog()) run_twice(Cat()) ''' Animal is running... Animal is running... Dog is running... Dog is running... Cat is running... Cat is running... '''

多态的含义:父类引用指向子类对象。

多态的作用:调用方只管调用,不管细节,当我们新增一种 Animal 的类型时,只要保证 run() 方法编写正确,不用管原来的代码是如何调用的。这符合“开闭”原则(Open Closed Principle,OCP):

对扩展开放(open for extension):允许新增 Animal 类的子类;
对修改关闭( closed for modification):新增了 Animal 类的子类,不需要修改依赖 Animal 类的 run_twice() 等函数。

特别注意的一点

对于静态语言(如 Java)来说,传入run_twice() 方法中的类型,需要是 Animal 类型,或者是 Animal 类型的子类型,否则,无法调用 run_twice() 方法。
而 Python 是一门动态语言,则不一定需要传入的是 Animal 类型或者其子类型,只要保证传入的对象有一个 run() 方法就可以了。

例如,这里我们定义一个火车Train 类,它有一个 run() 方法,它就可以传入 run_twice() 方法。

class Train(object): def run(self): print('Train is running...') run_twice(Train()) ''' Train is running... Train is running... '''

这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

9.4 获取对象信息

这里主要学习的是 type() 函数和 isinstance() 函数的使用。它们都是 Python 的内置函数。

type() 函数

type() 函数用来获取对象的类型,返回的是对应的 Class 类型。

它可以用于基本类型数据:

# 使用 type()来判断基本类型 print(type(123)) # print(type('hello')) # print(type(None)) # print(type(3.1415926)) # print(type(True)) #

可以判断指向函数或类的变量的类型:

print(type(abs)) # class Animal(object): pass a = Animal() print(type(a)) # b = Animal print(type(b)) #

判断 type() 函数作用的变量的类型是否相等:

print(type(123) == type(456)) # True print(type(123) == int) # True print(type('abc') == type('123')) # True print(type('abc') == str) # True print(type(6.18) == type(3.14)) # True print(type(6.18) == float) # True print(type(1 > 0) == type(2 > 1)) # True print(type(1 > 0) == bool) # True

可以看到,可以让基本数据类型的 intfloat 等参与比较。

判断 type() 函数作用的对象是否是函数:

import types # 引入 types 模块,这里需要它里面定义的一些常量 def fn(): pass print(type(fn) == types.FunctionType) # True print(type(abs) == types.BuiltinMethodType) # True print(type(lambda x: x + 1) == types.LambdaType) # True print(type((x for x in range(10))) == types.GeneratorType) # 这种是生成器列型 打印 :True

isinstance() 函数

class Fruit(object): pass class Apple(Fruit): pass class Hongfushi(Apple): pass f = Fruit() a = Apple() h = Hongfushi() print(isinstance(f, Fruit)) # True print(isinstance(a, Fruit)) # True print(isinstance(h, Fruit)) # True print(isinstance(a, Hongfushi)) # False # isinstance 用于基本数据类型 print(isinstance(123, int)) # True print(isinstance(True, bool)) # True print(isinstance(3.14, float)) # True print(isinstance('hello', str)) # True # isinstance 判断一个变量是否某些类型中的一种 print(isinstance([1, 2, 3], (list, tuple))) # True print('=' * 20, 'I am a divider', '=' * 20)

知识点:type() 函数和 isinstance() 函数的区别是什么?

type() 不会认为子类是一种父类类型,不考虑继承关系。

isinstance() 会认为子类是一种父类类型,考虑继承关系。

如果要判断两个类型是否相同推荐使用 isinstance()。

dir() 函数

获取一个对象的所有属性和方法,使用 dir() 函数,这也是 Python 中的一个内置函数。

print(dir('ABC'))

打印结果:

['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

可以看到返回的是一个 list,里面包含了str 对象的所有属性和方法。

# 获取一个对象的长度, 使用 len() 函数,内部就是调用对象的 __len__ 函数 print(len('ABC')) print('ABC'.__len__())

在自己的类中使用 __len__ 函数:

# 自己编写一个类,定义一个 __len__ 方法,也可以使用 len() 函数获取长度 class MyObject(object): def __len__(self): return 100 print(MyObject().__len__()) # 100 print(len(MyObject())) # 100

配合 getattr(), setattr() 和 hasattr(), 直接操作一个对象的状态

# 配合 getattr(), setattr() 和 hasattr(), 直接操作一个对象的状态 # 这三个都是内置函数 class MyClass(object): def __init__(self): self.x = 9 def power(self): return self.x * self.x obj = MyClass() # 判断有无属性 x? print(hasattr(obj, 'x')) # True print(obj.x) # 9 # 判断有无属性 y? print(hasattr(obj, 'y')) # False # 设置一个属性 y? setattr(obj, 'y', 19) # 再判断有无属性 y? print(hasattr(obj, 'y')) # True # 获取属性 y print(getattr(obj, 'y')) # 19 # 获取一个不存在的属性,抛出异常 # getattr(obj, 'z') # 此行抛出异常,如下所示 ''' File "attrs.py", line 36, in getattr(obj, 'z') AttributeError: 'MyClass' object has no attribute 'z' ''' # 获取属性,如果不存在,返回默认值 print(getattr(obj, 'z', -1)) # -1 # 获取对象的方法 print(hasattr(obj, 'power')) # True print(getattr(obj, 'power')) # <bound method MyClass.power of > fn = getattr(obj, 'power') print(fn) # <bound method MyClass.power of > print(fn()) # 81 9.5 实例属性和类属性 # 实例属性和类属性 class Student(object): # name 是类属性,归 Student 类所有 name = 'Student' wang = Student() print(wang.name) # Student li = Student() print(li.name) # Student

可以看到,对于 name,我们没有通过 __init__ 函数进行绑定,也没有通过对象绑定,但是每个实例都已经有了这个属性。

类属性作为计数器的例子:

# 为了统计学生人数,可以给Student类增加一个类属性,每创建一个实例,该属性自动增加: class Student(object): count = 0 def __init__(self, name): self.name = name Student.count = Student.count + 1

需要注意的是,不要对实例属性和类属性使用相同的名字,因为相同名字的实例属性会屏蔽掉类属性。

实例属性和类属性的区别:

实例属性属于各个实例,互不干扰;

类属性属于类所有,所有实例共享一个属性。


作者:willwaywang6



学习笔记 学习 python教程 廖雪峰python Python

需要 登录 后方可回复, 如果你还没有账号请 注册新账号