2. 模块、方法、类和对象

232 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

1. 模块、包、库的定义

模块(module):.py文件。

包(package):一组协同工作的python模块。文件夹[文件夹[文件夹[.py文件]]]

库(library):库是公开可调用的包。

2. import 和 from import的区别

import

在开始使用一个模块中的函数或者类之前,必须用import module1[module2...[modulen]]语句导入该模块。但是由于import只能导入包、子包、模块,不能导入模块中的函数、类、变量等。

因此如果我们想用某个模块中的函数或者类,必须在函数或者类前使用modulen.的前缀才能使用。

例如:

#使用random模块中的randint()函数生成1-100的随机数
import random
random_integer = random.randint(1, 100)

from import

from import可以导入模块、子包、包、类、函数、变量,from module1[module2...[modulen]] import modulen+1,function,class,variant 。使用这种方法如果导入了函数或类则不需要使用modulen.的前缀,相当于直接把函数或类拿进来了这个模块里。这个方法虽然方便但可读性不好。

例如:

#使用random模块中的randint()函数生成1-100的随机数
from random import randint
random_integer = randint(1, 100)

3. 类

定义一个类并创建实例

通常我们是这样认为的,创建一个类的实例才可以通过实例调用类内的方法和属性。

#定义Circle类
class Circle():
    pass

#创建实例
circle1= Circle()
circle2= Circle()

类属性和实例属性

类属性从属于一个类,它不属于任何的实例。不需要创建实例,就可以读取和修改这个值。

class Circle():
    pi=3.14

#你不需要创建一个实例,就能访问类属性
print(Circle.pi) #3.14
Circle.pi=3.14159
print(Circle.pi)#3.14159

#你也可以创建一个实例去访问类属性
circle1=Circle()
print(circle1.pi) #3.14159
#你若通过实例去修改实际上是给circle1创建了一个与类属性同名的实例属性。
circle1.pi=3.1
print(Circle.pi)#3.14159 跟随类的属性并没有改变
print(circle1.pi)#3.1

那么实例属性,顾名思义是从属于实例的。

#添加实例属性方法一
class Circle():
    pi=3.14

circle1=Circle()
#你完全可以通过实例. 的方式去添加实例属性
circle1.r=3
print(circle1.r)

但是我们通常会认为方法一这样添加属性给每个实例,未免也太麻烦了。既然类意为大家是一个模子里刻出来的,那么创建实例的时候一起添加都有的属性好啦。

定义类的时候还没有实例存在,创建实例时circle1=Circle(3),会自动调用 _init_(self,r)传入实例和参数,此时self就被激活,self就代表类的实例cilcle1,实例属性r被赋予了值。

#添加实例属性方法二
class Circle():
    pi=3.14

    def __init__(self,r):
        self.r=r

circle1=Circle(3)
print(circle1.r)

类的实例方法

self的意义是什么,我理解为:当创建一个实例时,self=被创建的实例,例如这里的self=circle1。实例通过 self 去绑定属于自己的实例属性和实例方法,这样各个实例之间不会冲突,各用各自的属性和方法。

就比如:一创建实例,会自动调用_init_方法,通过self,实例对象circle1绑定自己的init方法,又添加了自己的属性r:self.r=r → cilcle1.r=r

通过实例访问的类内方法叫做实例方法,如get_area(self,p)_init_是特殊的实例方法。

实例方法与类外的函数不同在于,第一个参数必须设置为self,实例方法互相调用要用self.,实例方法调用实例属性要用self.。很容易理解,如我们上面所说的,因为实例属性和实例方法都要跟随着实例的。

class Circle():
    pi=3.14

    def __init__(self,r):
        self.r=r
    def get_area(self,p):
        self.p=p
        area=self.pi*self.r*self.r 
        print(area)

circle1=Circle(3)
circle1.get_area(4)
class Circle():
    pi=3.14

    def __init__(self,r):
        self.r=r
    def sum(self):
        s=2*self.pi*self.r
        return s
    def get_round(self):
        #类中函数相互调用要加self例如:self.sum(),
        #这是因为如果调用get_round要把实例传进去激活self。
        round=self.sum()
        return round

circle1=Circle(3)
round=circle1.get_round()
print(round)

记录:3.7早晨刷题的时候纠结了一下:到底什么时候应该加上self,什么时候不加self?为什么class TreeNode__init__中的变量都加self,而SolutionmaxDepth中的depth、root不需要self

换个思维应该认为self是全局变量,如果变量前面加了self,那么在任何实例方法(非staticmethod和calssmethod)就都可以访问这个变量了,如果没有加self,只有在当前函数内部才能访问这个变量。

class TreeNode中其他方法也会调用val、left、right。而Solution则不需要。

#求深度
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class Solution:
    #maxDepth方法是我写的    
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        depth=0
        if root:
            depth=max(self.maxDepth(root.left),self.maxDepth(root.right))+1
        
        return depth

我可以像上面那样在__init__中传入参数: def __init__(self, val=0, left=None, right=None)然后用self绑定。也可以像下面这样不需要传参,凡是加上了self,就代表着与当前的实例是绑定的。

class Tree:
   def __int__(self):
       self.val=0
       self.left=None
       self.right=None


tree1=Tree()

tree1.val=1
tree1.left=2
tree1.right=3

print(str(tree1.val)+"→"+str(tree1.left)+"→"+str(tree1.right)) #1→2→3