Python基础学习(三)

面向对象

Python从设计之初就已经是一门面向对象的语言;面向对象能有效提高编程的效率,通过封装技术,消息机制可以像搭积木的一样快速开发出一个全新的系统。面向对象是指一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的集合。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。

PS. 其实R语言也有面向对象编程,也有面向对象的3个特征:封装、继承、多态

Python类的使用比较广泛,总能在各个Python代码中看到(尤其是伪代码),根据资料理解下Python面向对象的几个概念和简单的使用

具体名字概念(类、方法、实例化、对象等基础名词)可以看:Python3 面向对象,其中主要的就是使用类和对象来编程

其中对于类变量和实例变量最初有点迷糊,但看了下面的例子后就清晰了

class foo:
    def __init__(self):
        self.x = 10
    def add(self, y):
        return self.x + y

f = foo()
print(f.x)  #5

f.a = 10
foo.a = 20
print(f.x, f.a, foo.a)  #5 10 20

foo.b = 30
f.c = 40

f2 = foo()
print(f2.x) # 5
print(f2.a) # 20
print(f2.b) # 30
print(f2.c) # error 'foo' object has no attribute 'c'

以上例子可看出,f.af.c为实例变量,其只能作用于某一个实例上,因此在f2.c就报错了;而foo.afoo.b为类变量,其可以被不同对象继承

以上述foo类为例,f = foo()是实例化类,f.x则是属性引用(在类中,属性是用变量来表示的);__init__是特殊方法(在类实例化时自动调用)而add则是自定义方法,方法可以直接访问实例的数据;self代表类的实例,比如self.x就是实例变量,其也是类的方法和普通函数唯一的差别之处,而self.class则是类,也可以将self替换成其他字符,但是常用一般就这个了

对于方法的调用,在类实例化后可像函数那样使用,如:

f = foo()
print(f.add(10))

在类中可以增加私有变量,使得其在外部无法被访问,如在print(p.__secret)会报错'private' object has no attribute '__secret'

class private:
    __secret = 10
    public = 20

p = private()
print(p.public)
print(p.__secret)

类的可以继承,这也是能有效的提高编程的效率,可以减少一些重复的编程工作,即子类可以继承父类的(其实也就是将多个公共的方法放到父类中,然后子类继承父类),如:

class common:    
    def __init__(self):
        self.x = 1
        self.y = 2

    def add(self, w):
        return self.x + self.y + w

c = common()
print(c.add(10))

class foo1(common):
    def __init__(self):
        common.__init__(self)
        self.x += 1
        self.y += 2

f1 = foo1()
print(f1.add(10))

从上面代码可看出,父类是common,子类在调用父类时用class foo1(common)表示foo1类继承了common类,然后用common.__init__这种形式调用父类的属性,并且不需要再写一遍add方法即可在子类中使用

模块与包

类似于R包,Python也有将定义的函数和变量封装的封装的方法-模块,以便在其他程序中调用

比如在app.py脚本中定义了一个函数:

def func(x,y):
print(x, "+", y, "=", x + y)

然后在test.py脚本中调用app.py中的func函数,同时在app.py所在目录下会生成一个__pycache__文件夹

import app
app.func(*(1,2))
>1 + 2 = 3
print(app.__name__)
>app

如果不是在当前目录下的模块,可以用sys.path查看下Python对于模块的搜索路径有哪些

import sys
print(sys.path)

然后可以用dir()函数来查看模块内定义的名称

dir(app)

Python不仅像上述那样调用方法,还可以调用模块变量和类变量等,如新建一个app_class.py

a = 1
b = 2

print(a + b)

def func(x,y):
    print(x, "+", y, "=", x + y)

class Myclass:
    i = 123

    def f(self):
        return("Learning Python")

    def cf(self):
        print("cf:", self.cf)

然后在test.py中调用app_class.py,即import app,输出1 + 2 = 3,如果再一次import app则无输出,这是因为模块只有第一次被导入的时候才会被执行,从输出的结果上可看出,模块变量在模块初始化的时候就被执行了,类变量其实也一样,而函数和类的方法则是在初始化后被调用时才执行

app.a
app.func(3,5)
app.Myclass.f(1)

如果你将__name__设置为__main__,则可以将模块跟脚本一样执行可接受外部参数,如在代码最后添加一些脚本输出:

if __name__ == "__main__":
    import sys
    print("Learning Python3", sys.argv[1])

我一直粗略的把R包理解成一大堆R函数的集合,Python对于包的定义则是:

包是一种管理Python模块命名空间的形式

R中是以::来精确调用不同R包下的函数,而Python则是用.来实现的

Python包的结构如下:

package1/
    __init__.py
    subPack1/
        __init__.py
        module1_1.py
        module1_2.py
        module1_3.py
    subPack2/
        __init__.py
        module2_1.py
        module2_2.py

Python包中必须包含一个__init__.py文件,用于初始化代码或者__all__变量赋值;一般我们导入包中特定的子模块会用这种方法:from docx.shared import Inches,其中shared是docx包的子模块,Inches则是其中的函数;当__init__.py文件写入__all__ = ["XX1", "XX2", "XX3"]时,那么在用from package import *时,只会导入XX1/XX2/XX3子模块,如果没定义的话,则不会导入这三个子模块,而是将包中的所有定义的内容都导入

参考资料:
Python3 面向对象
Python3 模块
http://www.cnblogs.com/tqsummer/archive/2011/01/24/1943273.html

本文出自于http://www.bioinfo-scrounger.com转载请注明出处