Python简明教程学习笔记[三]

回目录

. Python的面向对象编程


3.1 Python的类的基础


3.1.1 创建一个类

#!/usr/bin/python
# Filename: simplestclass.py
class Person:
    pass # An empty block
p = Person()	 # 创建类对象
print(p)
输出
$ python simplestclass.py
<__main__.Person instance at 0xf6fcb18c> 


我们使用class语句后跟类名,创建了一个新的类。这后面跟着一个缩进的语句块形成类体在这个例子中,我们使用了一个空白块,它由pass语句表示。

接下来,我们使用类名后跟一对圆括号来创建一个对象/实例。(我们将在下面的章节中学习更多的如何创建实例的方法)。为了验证,我们简单地打印了这个变量的类型。它告诉我们我们已经在__main__模块中有了一个Person类的实例。可以注意到存储对象的计算机内存地址也打印了出来。


3.1.2 self 相当于C++this指针

          

       在类方法的定义时需要在第一个参数位置添加self, 而在调用时不需要为该参数赋值Python自动为我们添加类对象的指针给self.(这和C++的是一样的)

这个特别的变量指对象本身,按照惯例它的名称是self


3.1.3 使用类对象的方法


11.2 使用对象的方法

#!/usr/bin/python
# Filename: method.py
class Person:
    def sayHi(self):	 # 定义类方法, 注意这个self
        print 'Hello, how are you?'
p = Person()
p.sayHi()
# This short example can also be written as Person().sayHi() 
(源文件:code/method.py)
输出
$ python method.py
Hello, how are you?

这里我们看到了self的用法。注意sayHi方法没有任何参数,但仍然在函数定义时有self


3.1.4 __init__方法(相当于C++中构造函数)


__init__方法在类的一个对象被建立时,马上运行相当于C++中构造函数。你可以在里面做一些初始化工作 。注意,这个名称的开始和结尾都是双下划线。

使用__init__方法

11.3 使用__init__方法

#!/usr/bin/python
# Filename: class_init.py
class Person:
    def __init__(self, name):	 # 类方法定义时, 第一个参数都是self
        self.name = name	 # 初始化工作
# 注意name不需要在类中声明, 直接赋值就代表声明了
    def sayHi(self):
        print('Hello, my name is', self.name)
p = Person('Swaroop')	 # 使用时不需要填入self
p.sayHi()
# This short example can also be written as Person('Swaroop').sayHi() 
输出
$ python class_init.py
Hello, my name is Swaroop 

我们把__init__方法定义为取一个参数name(以及普通的参数self)。


3.1.5 类与对象的方法

        类与对象的变量只是与类和对象的名称空间 绑定 的普通变量,即这些名称只在这些类与对象的前提下有效。

有两种类型的域 ——类的变量和对象的变量,它们根据是类还是对象拥有这个变量而区分。

类的变量相当于C++类的静态变量对象的变量相当于C++类的非静态变量.

使用类与对象的变量

11.4 使用类与对象的变量

#!/usr/bin/python
# Filename: objvar.py
class Person:
    '''Represents a person.'''	 # 这个干嘛的
    population = 0	 # 这个就是类的变量了
    def __init__(self, name):	 # 类构造函数
        '''Initializes the person's data.'''
        self.name = name	 # self.name 就是对象的变量了
        print('(Initializing %s)' % self.name)
        # When this person is created, he/she
        # adds to the population
        Person.population += 1
    def __del__(self):	 # 类的析构函数
        '''I am dying.'''
        print('%s says bye.' % self.name)
        Person.population -= 1
        if Person.population == 0:
            print('I am the last one.')
        else:
            print('There are still %d people left.' % Person.population)
    def sayHi(self):
        '''Greeting by the person.
        Really, that's all it does.'''
        print('Hi, my name is %s.' % self.name)
    def howMany(self):
        '''Prints the current population.'''
        if Person.population == 1:
            print('I am the only person here.')
        else:
            print('We have %d persons here.' % Person.population)
swaroop = Person('Swaroop')
swaroop.sayHi()
swaroop.howMany()
kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()
swaroop.sayHi()
swaroop.howMany() 
输出
$ python objvar.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one. 

         Python中所有的类成员(包括数据成员)都是 公共的 ,所有的方法都是 有效的 。

只有一个例外:如果你使用的数据成员名称以 双下划线前缀 比如__privatevarPython的名称管理体系会有效地把它作为私有变量。

这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python所要求的(与双下划线前缀不同)。


3.1.6 继承


11.5 使用继承

#!/usr/bin/python
# Filename: inherit.py
class SchoolMember:
    '''Represents any school member.'''
    def __init__(self, name, age):	 # 构造函数
        self.name = name
        self.age = age
        print('(Initialized SchoolMember: %s)' % self.name)
    def tell(self):
        '''Tell my details.'''
        print('Name:"%s" Age:"%s"' % (self.name, self.age))
class Teacher(SchoolMember):	 # 继承
    '''Represents a teacher.'''
    def __init__(self, name, age, salary):
        SchoolMember.__init__(self, name, age)	# 调用父类的构造函数, 这里调用时有self的
        self.salary = salary
        print('(Initialized Teacher: %s)' % self.name)
    def tell(self):	 # 重载了父类的tell方法
        SchoolMember.tell(self)
        print('Salary: "%d"' % self.salary)
class Student(SchoolMember):
    '''Represents a student.'''
    def __init__(self, name, age, marks):
        SchoolMember.__init__(self, name, age)	# 调用父类的构造函数, 这里调用时有self的
        self.marks = marks
        print('(Initialized Student: %s)' % self.name)
    def tell(self):	 # 重载了父类的tell方法
        SchoolMember.tell(self)
        print('Marks: "%d"' % self.marks)
t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 22, 75)
print() # prints a blank line
members = [t, s]
for member in members:	 # 循环调用tell
    member.tell() # works for both Teachers and Students 
输出
$ python inherit.py
(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)
Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"22" Marks: "75" 

为了使用继承,我们把基本类的名称作为一个元组跟在定义类时的类名称之后。然后,我们注意到基本类的__init__方法专门使用self变量调用,这样我们就可以初始化对象的基本类部分。这一点十分重要——Python不会自动调用基本类的constructor你得亲自专门调用它。这里是需要self传递给父类的__init__函数的

我们还观察到我们在方法调用之前加上类名称前缀,然后把self变量及其他参数传递给它。

注意,在我们使用SchoolMember类的tell方法的时候,我们把TeacherStudent的实例仅仅作为SchoolMember的实例。

Python总是首先查找子类的方法如果它不能在导出类中找到对应的方法,它才开始到基本类中逐个查找。基本类是在类定义的时候,在元组之中指明的

3.2. Python的输出输入


3.2.1 Python读写文件

         你可以通过创建一个file类的对象来打开一个文件,分别使用file类的readreadlinewrite方法来恰当地读写文件。对文件的读写能力依赖于你在打开文件时指定的模式。最后,当你完成对文件的操作的时候,你调用close方法来告诉Python我们完成了对文件的使用。

#!/usr/bin/python
# Filename: using_file.py
poem = '''\
Programming is fun
When the work is done
if you wanna make your work also fun:
        use Python!
'''
f = open('poem.txt', 'w') # open for 'w'riting 打开文件写方式
f.write(poem) # write text to file写入文本到文件
f.close() # close the file关闭文件
f = open('poem.txt')#再次打开文件
# if no mode is specified, 'r'ead mode is assumed by default
while True:
    line = f.readline()	 # 循环读取文件, 知道读取到EOF文件尾
    if len(line) == 0: # Zero length indicates EOF
        break
    print(line)
    # Notice comma to avoid automatic newline added by Python
f.close() # close the file 


3.2.2 储存器(用户Python对象的序列化/持久化)


        Python提供一个标准的模块,称为pickle。使用它你可以在一个文件中储存任何Python对象,之后你又可以把它完整无缺地取出来。这被称为 持久地 储存对象。

还有另一个模块称为cPickle,它的功能和pickle模块完全相同,只不过它是用C语言编写的,因此要快得多(比pickle1000倍)。你可以使用它们中的任一个,而我们在这里将使用cPickle模块。记住,我们把这两个模块都简称为pickle模块。

#!/usr/bin/python
# Filename: pickling.py
#import cPickle as p 命名空间使用as来重命名
import pickle as p
shoplistfile = 'shoplist.data'
# the name of the file where we will store the object
shoplist = ['apple', 'mango', 'carrot']
# Write to the file 写入Python对象到文件
f = open(shoplistfile, 'wb')
p.dump(shoplist, f) # dump the object to a file
f.close()
del shoplist # remove the shoplist
# Read back from the storage 重新读取
f = open(shoplistfile, 'rb')
storedlist = p.load(f)
print(storedlist)
输出
$ python pickling.py
['apple', 'mango', 'carrot'] 


3.3 异常处理


3.3.1用 try..finally 捕捉异常

#!/usr/bin/python
# Filename: try_except.py
import sys
try:
    s = input('Enter something --> ')
except EOFError:	 # 这里指定捕捉指定类型的异常
    print('\nWhy did you do an EOF on me?')
    sys.exit() # exit the program
except:	 # 捕捉所有类型的异常.
    print('\nSome error/exception occurred.')
    # here, we are not exiting the program
print('Done')

我们把所有可能引发错误的语句放在try块中,然后在except从句/块中处理所有的错误和异常。except从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。如果没有给出错误或异常的名称,它会处理 所有的 错误和异常对于每个try从句,至少都有一个相关联的except从句。

如果某个错误或异常没有被处理,默认的Python处理器就会被调用。它会终止程序的运行,并且打印一个消息,我们已经看到了这样的处理。你还可以让try..catch块关联上一个else从句。当没有异常发生的时候,else从句将被执行。我们还可以得到异常对象,从而获取更多有个这个异常的信息。


3.3.2 抛出异常


        你可以使用raise语句 引发 异常。你还得指明错误/异常的名称和伴随异常 触发的 异常对象。你可以引发的错误或异常应该分别是一个ErrorException类的直接或间接导出类。

#!/usr/bin/python
# Filename: raising.py
# 定义一个异常子类
class ShortInputException(Exception):
    '''A user-defined exception class.'''
    def __init__(self, length, atleast):
        Exception.__init__(self)
        self.length = length
        self.atleast = atleast
try:
    s = input('Enter something --> ')
    if len(s) < 3:
        raise ShortInputException(len(s), 3)	 # 如果输入长度小于3, 使用 raise 抛出一个异常
    # Other work can continue as usual here
except EOFError:
    print('\nWhy did you do an EOF on me?')
except ShortInputException as x:	 # 注意x 代表异常类对象的名称
    print('ShortInputException: The input was of length %d, \
          was expecting at least %d' % (x.length, x.atleast))
else:
    print('No exception was raised.')

3.3.3 try..finally

        

        在一个try块下,你可以同时使用except从句和finally块。如果你要同时使用它们的话,需要把一个嵌入另外一个。

#!/usr/bin/python
# Filename: finally.py
import time
try:
    f = open('poem.txt')
    while True: # our usual file-reading idiom
        line = f.readline()
        if len(line) == 0:
            break
        time.sleep(2)
        print(line)
finally:
    f.close()
print('Cleaning up...closed the file')
输出
$ python finally.py
Programming is fun
When the work is done
Cleaning up...closed the file
Traceback (most recent call last):
  File "finally.py", line 12, in ?
    time.sleep(2)
KeyboardInterrupt 

         我们进行通常的读文件工作,但是我有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些(Python由于其本质通常运行得很快)。在程序运行的时候,按Ctrl-c中断/取消程序。

我们可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍然被执行,把文件关闭.

也就是说finally块总是会执行的无论异常有没有发生.


3.4 Python的标准库


3.4.1 sys模块

 

          sys模块包含系统对应的功能。

14.1 使用sys.argv

#!/usr/bin/python
# Filename: cat.py
import sys
def readfile(filename):
    '''Print a file to the standard output.'''
    f = open(filename)
    while True:
        line = f.readline()
        if len(line) == 0:
            break
        print(line) # notice comma
    f.close()
# Script starts from here
if len(sys.argv) < 2:
    print('No action specified.')
    sys.exit()
if sys.argv[1].startswith('--'):
    option = sys.argv[1][2:]
    # fetch sys.argv[1] but without the first two characters
    if option == 'version':
        print('Version 1.2')
    elif option == 'help':
        print('''\
This program prints files to the standard output.
Any number of files can be specified.
Options include:
  --version : Prints the version number
  --help    : Display this help''')
    else:
        print('Unknown option.')
    sys.exit()
else:
    for filename in sys.argv[1:]:
        readfile(filename) 

Python程序运行的时候,即不是在交互模式下,在sys.argv列表中总是至少有一个项目。它就是当前运行的程序名称,作为sys.argv[0](由于Python0开始计数)。其他的命令行参数在这个项目之后。

为了使这个程序对用户更加友好,我们提供了一些用户可以指定的选项来了解更多程序的内容。我们使用第一个参数来检验我们的程序是否被指定了选项。如果使用了--version选项,程序的版本号将被打印出来。类似地,如果指定了--help选项,我们提供一些关于程序的解释。我们使用sys.exit函数退出正在运行的程序。和以往一样,你可以看一下help(sys.exit)来了解更多详情。

如果没有指定任何选项,而是为程序提供文件名的话,它就简单地打印出每个文件地每一行,按照命令行中的顺序一个文件接着一个文件地打印。

顺便说一下,名称cat是 concatenate 的缩写,它基本上表明了程序的功能——它可以在输出打印一个文件或者把两个或两个以上文件连接/级连在一起打印。

sys.version字符串给你提供安装的Python的版本信息。

sys.version_info元组则提供一个更简单的方法来使你的程序具备Python版本要求功能。

[swaroop@localhost code]$ python
>>> import sys
>>> sys.version
'2.3.4 (#1, Oct 26 2004, 16:42:40) \n[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)]'
>>> sys.version_info
(2, 3, 4, 'final', 0)

对于有经验的程序员,sys模块中其他令人感兴趣的项目有sys.stdinsys.stdoutsys.stderr它们分别对应你的程序的标准输入、标准输出和标准错误流。


3.4.2 os模块


这个模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在LinuxWindows下运行。一个例子就是使用os.sep可以取代操作系统特定的路径分割符。

下面列出了一些在os模块中比较有用的部分。它们中的大多数都简单明了。

os.name字符串指示你正在使用的平台。比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'

os.getcwd()函数得到当前工作目录,即当前Python脚本工作的目录路径。

os.getenv()os.putenv()函数分别用来读取和设置环境变量。

os.listdir()返回指定目录下的所有文件和目录名。

os.remove()函数用来删除一个文件。

os.system()函数用来运行shell命令。

os.linesep字符串给出当前平台使用的行终止符。例如,Windows使用'\r\n'Linux使用'\n'Mac使用'\r'

os.path.split()函数返回一个路径的目录名和文件名。

>>> os.path.split('/home/swaroop/byte/code/poem.txt')

('/home/swaroop/byte/code', 'poem.txt') 

os.path.isfile()os.path.isdir()函数分别检验给出的路径是一个文件还是目录。类似地,os.path.existe()函数用来检验给出的路径是否真地存在。

你可以利用Python标准文档去探索更多有关这些函数和变量的详细知识。你也可以使用help(sys)等等。


3.5 Python其他的一些知识


3.5.1 一些特殊的方法


特殊的方法(我的理解就是框架方法了设定好了框架你在上面填充好就可以了)

在类中有一些特殊的方法具有特殊的意义,比如__init____del__方法,它们的重要性我们已经学习过了。

一般说来,特殊的方法都被用来模仿某个行为。例如,如果你想要为你的类使用x[key]这样的索引操作(就像列表和元组一样),那么你只需要实现__getitem__()方法就可以了。想一下,Python就是对list类这样做的!

下面这个表中列出了一些有用的特殊方法。如果你想要知道所有的特殊方法,你可以在《Python参考手册》中找到一个庞大的列表。

15.1 一些特殊的方法

名称 说明 

__init__(self,...) 这个方法在新建对象恰好要被返回使用之前被调用。 (构造函数)

__del__(self) 恰好在对象要被删除之前调用。 (析构函数)

__str__(self) 在我们对对象使用print语句或是使用str()的时候调用。 

__lt__(self,other) 当使用 小于 运算符(<)的时候调用。类似地,对于所有的运算符(+>等等)都有特殊的方法。 

__getitem__(self,key) 使用x[key]索引操作符的时候调用。 相当于操作符[]

__len__(self) 对序列对象使用内建的len()函数的时候调用。 


3.5.2 单语句


每一个语句块是通过它的缩进层次与其它块区分开来的(相当于C++中的花括号)。但是如果你的语句块只包含一句语句,那么你可以在条件语句或循环语句的同一行指明它(此时不需要通过缩进也可以分开代码块)

>>> flag = True

>>> if flag: print 'Yes'

...

Yes 

但这可能是一种不好的习惯尽量少用.


3.5.3 列表综合


通过列表综合,可以从一个已有的列表导出一个新的列表。

例如,你有一个数的列表,而你想要得到一个对应的列表,使其中所有大于2的数都是原来的2

对于这种应用,列表综合是最理想的方法。

15.1 使用列表综合

#!/usr/bin/python
# Filename: list_comprehension.py
listone = [2, 3, 4]
listtwo = [2 * i for i in listone if i > 2]	 # 注意这里的格式
print(listtwo)
输出
$ python list_comprehension.py
[6, 8] 

它如何工作

这里我们为满足条件(if i > 2)的数指定了一个操作(2*i),从而导出一个新的列表。注意原来的列表并没有发生变化。在很多时候,我们都是使用循环来处理列表中的每一个元素,而使用列表综合可以用一种更加精确、简洁、清楚的方法完成相同的工作


3.5.4 在函数中接收元组和列表


当要使函数接收元组或字典形式的参数的时候,有一种特殊的方法,它分别使用***前缀。这种方法在函数需要获取可变数量的参数的时候特别有用。

>>> def powersum(power, *args):
...     '''Return the sum of each argument raised to specified power.'''
...     total = 0
...     for i in args:
...          total += pow(i, power)
...     return total
...
>>> powersum(2, 3, 4)
25
>>> powersum(2, 10)
100 

由于在args变量前有*前缀,所有多余的函数参数都会作为一个元组存储在args中。如果使用的是**前缀,多余的参数则会被认为是一个字典的键/值对。


3.5.5 lambda形式(这个不是很明白)


lambda语句被用来创建新的函数对象,并且在运行时返回它们。

15.2 使用lambda形式

#!/usr/bin/python
# Filename: lambda.py
def make_repeater(n):
    return lambda s: s*n	 #  lambda 
twice = make_repeater(2)	 # 设置 n是2
print(twice('word'))	 #  word是lambda的s
print(twice(5))
输出
$ python lambda.py
wordword
10 

它如何工作

这里,我们使用了make_repeater函数在运行时创建新的函数对象,并且返回它。lambda语句用来创建函数对象。本质上,lambda需要一个参数,后面仅跟单个表达式作为函数体,而表达式的值被这个新建的函数返回。注意,即便是print语句也不能用在lambda形式中,只能使用表达式。


3.5.6 exec和eval语句(这个强大啊)

         exec语句用来执行储存在字符串或文件中的Python语句。例如,我们可以在运行时生成一个包含Python代码的字符串,然后使用exec语句执行这些语句。下面是一个简单的例子。

>>> exec('print "Hello World"')
Hello World 

eval语句用来计算存储在字符串中的有效Python表达式。

下面是一个简单的例子。

>>> eval('2*3')
6 

这两个语句强大相当于字符串也可以作为命令执行C++中必须自己写代码实现的而对于解析性的语言这是很简单的事情.

现在我的理解结合 lambda来试一下:

#!/usr/bin/python
# Filename: lambda1.py
def make_repeater(n):
    return lambda s: s*n
twice = make_repeater(2)
print(twice(exec('print("word")')))
print(twice(5))

会发生异常


3.5.7 assert语句


(C++中也有这个东西调试版时有效就是用来验证用的)

assert语句用来声明某个条件是真的。例如,如果你非常确信某个你使用的列表中至少有一个元素,而你想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。当assert语句失败的时候,会引发一个AssertionError

>>> mylist = ['item']
>>> assert len(mylist) >= 1
>>> mylist.pop()
'item'
>>> assert len(mylist) >= 1
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError 

3.5.8 repr函数


repr函数用来取得对象的规范字符串表示。反引号(也称转换符,在键盘左上角与~同一个键)可以完成相同的功能。注意,在大多数时候有eval(repr(object)) == object

>>> i = []
>>> i.append('item')
>>> `i`
"['item']"
>>> repr(i)
"['item']" 

基本上,repr函数和反引号用来获取对象的可打印的表示形式。你可以通过定义类的__repr__方法来控制你的对象在被repr函数调用的时候返回的内容。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值