python类与对象 类与对象

创建类

通过关键字class创建一个Player类,来个栗子

class Player:
    pass

创建对象

通过类实例化两个对象,来个栗子

class Player:
    pass

p1 = Player()
p2 = Player()
print(p1) #<__main__.Player object at 0x00000000020E2198>
print(p2) #<__main__.Player object at 0x00000000020E2E48>

添加属性

举个栗子

class Player:
    pass

p1 = Player()
p1.name = "tom"
p1.lives = 3
print(p1.name, p1.lives) #tom 3

面向对象的重点在于不同对象之间的交互

为类添加一些行为,当这些行为触发时,可以改变对象的属性,举个栗子

class Player:
    def add_one_live(self):
        self.lives += 1

p = Player()
p.lives = 3
p.add_one_live()
print(p.lives) #4

参数self

self是对方法所调用对象的引用

类中定义的函数,其第一个形参一般都要显示的传入self,否则在通过类实例调用函数时会报错

class Player:
    def add_one_live():
        self.lives += 1

p = Player()
p.add_one_live() #TypeError: add_one_live() takes 0 positional arguments but 1 was given

对象初始化

python类对象的初始化一般包含两个部分:构造函数__new__和对象数据的初始化即初始化方法__init__,

对象的创建是通过构造函数__new__,对象数据的初始化是通过初始化函数__init__,

有的python内置类没有__init__方法,而直接在__new__方法中创建和初始化,如Tuple。

class Player:
    def __init__(self, lives):
        self.lives = lives

    def add_one_live(self):
        self.lives += 1

p = Player(3)
print(p.lives) #3
p.add_one_live()
print(p.lives) #4

文档注释

可以在每个类、函数头定义语句的下一行添加字符串

来个栗子

class Player:
    'Represents a player in the game'
    def __init__(self, lives):
        self.lives = lives

    def add_one_live(self):
        """add one live
        when the player passed one game checkpoint"""
        self.lives += 1

说明:python -i filename.py,加载这个文件到交互解释器中

   help(Player) 查看这个类的格式文档

模块和包

模块

一个python文件就是一个模块

模块的导入

(1)导入整个模块, 在products.py模块需要实例化来自database.py模块中的Database类

import database
db = database.Database()

(2)导入模块中的具体类

from database import Database
db = Database()

(3)将导入的类重命名

from database import Database as DB
db = DB()

(4)一次导入模块中的多个类

from database import Database, Query

(5)禁止使用import *

from database import *

说明:如果使用,将花费更多的时间去找出类的位置,丧失某些编辑器的代码自动补全,跳转到自定义类位置等功能

一个包是一个目录下模块的集合,目录的名字就是包的名字,

我们只需在目录下添加一个名为__init__.py的文件就可以告诉python这个目录是一个包

taobao/
    main.py
    ecommerce/
        __init__.py
        database.py
        products.py
        contact/
            __init__.py
            email.py
        payments/
            __init__.py
            square.py
            stripe.py
            paypal.py

来个栗子

说明:目录中一共有3个包,在taobao这个目录下有1个ecommerce包,在ecommerce目录下有1个payments包和1个contact包

绝对导入

指定我们想要导入的模块或函数的完整路径,比如我们想要访问products模块中的Product类,可以用以下三种方法进行绝对导入

import ecommerce.products
product = ecommerce.products.Product()

or

from ecommercek.products import Product
product = Product

or

from ecommerce import products
product = products.Product()

说明:这些语句可以在taobao目录下的任何模块中运行

 如果products模块下有10个左右的类是我需要使用的,通常使用第三种方法导入

如果products模块下只有2个类是我需要的,通常使用第二种方法导入

相对导入

应用1,寻找与当前模块在位置上有相对关系的类或函数,比如我们想在products模块中导入与之相邻的database模块中的Database类

from .database import Database

点号表示使用当前包内的database模块,即ecommerce包

应用2,如果我们要在paypal模块中使用父包中的database模块,可以用两点号来实现

from ..database import Database

当然,我们也可以利用更多的点来导入更高层级包中的模块,也可以一边后退回到其他较深层

应用3,比如,我们想在paypal模块中使用contact包下的email模块中的send_email函数

from ..contact.email import send_email

说明:..contact.email用了两个点号回到了payments包的上一层,然后用正常的package.module语法回到了contact包那一层

我们也可以从包中导入代码

应用4,比如,database模块中有一个变量db,会有从许多不同的包来访问,import ecommerace.db显然比import ecommerce.database.db更方便

在我们的例子中,如果ecommerce/__init__.py中包含如下一行代码

from .database import db

那么我们可以在main.py和其他任何文件中直接访问ecommerce包中的db属性

from ecommerce import db

__init__.py文件是与其他模块通信的主要节点,但是代码可以在内部组织为几个不同的模块或子包。

组织模块

栗子1,如果我们想要在多个模块中导入Database类并进行实例化,我们可以在多个模块中导入类DataBase并进行实例化,

但是更为合理的做法是只有一个全局的Database实例对象,database.py模块代码如下

class Database:
    pass

database = Database()

分析

但是这存在一个问题,由于模块中调用的代码都会在导入时立即执行,当我们在对database.py模块导入时,Database实例对象就立即被创建,

这通常发生在程序启动时,而数据库的连接又需要时间,这会增加程序启动的时间。

那我们怎么办?当然来推迟Database对象实例的创建时间。

class Database:
    pass

database = None

def init_database():
    global database
    database = Database()

栗子2,一个程序的main.py模块,需要从其他程序中的模块中导入某些函数或类,然而一旦导入,所有这些模块层的代码都会立即执行,

但是我们只想访问其中的几个函数。

分析:为了解决这一问题,我们可以将启动的代码放到一个函数中,一般叫main,只有模块作为脚本运行时才执行这一函数。

class Util:
    pass

def main():
    util = Util()
    print(util)
    pass

if __name__ == '__main__':
    main()

说明:将所有的脚本代码包含在if __name__ == '__main__':下,以防止你写的函数被其他的代码导入。

方法定义在类中,类定义在模块中,模块存在于包中。

说明:这是python一种典型的顺序,类可以定义在任何地方如定义在一个函数的内部,这通常用于一次性对象。 

参考资料:《python3面向对象编程》