方法

定义在类中的函数称为方法。根据调用的方式不同,分为:

  • 对象方法
  • 类方法
  • 静态方法
  • 魔术方法。

对象方法

定义在类中的普通函数,一般通过对象调用称为对象方法。

对象方法的定义

为了讲清楚对象方法的定义和调用,先看下面的案例

案例:

定义函数my_print,它接收一个Point对象,然后打印这个点的x,y坐标。

def my_print(point):
    print('({},{})'.format(point.x, point.y))
    
p = Point()
p.x = 1
p.y = 2
my_print(p)

输出:

(1,2)

在定义函数distance,它接收两个Point对象,然后返回这两个点的距离。

def distance(p1, p2):
    return ((p1.x-p2.x)**2 + (p1.y-p2.y)**2)**0.5

p1 = Point()			# 实例化
p2 = Point()			# 实例化
p1.x = 1				# 赋值x坐标
p1.y = 2				# 赋值y坐标
p2.x = 3				# 赋值x坐标
p2.y = 4				# 赋值y坐标
res = distance(p1,p2)
print(res)

输出:

2.8284271247461903

观察上面的两个函数,发现它们都接收一个或多个Point的对象作为参数。为了显式的加强这样的联系,我们可以将它们定义在Point的类中。

class Point:
    """
    表示平面坐标系中的一个点
    """
    name = '点'

    def my_print(point):
        print('({},{})'.format(point.x, point.y))

    def distance(p1, p2):
        return ((p1.x-p2.x)**2 + (p1.y-p2.y)**2)**0.5

对象方法的调用

对象方法像属性一样,可以通过句点法进行调用。

类.方法名(参数)
对象.方法名(参数)

通过类调用时,和普通函数没有区别。

# 接上面的代码
# 更新了类,再次实例化对象
point = Point()
point.x = 1
point.y = 2
p1 = Point()
p2 = Point()
p1.x = 1
p1.y = 2
p2.x = 3
p2.y = 4

通过类调用(一般不会这么调用)

Point.my_print(point)
res = Point.distance(p1, p2)
print(res)

输出:

(1,2)
2.8284271247461903

通过对象调用对象方法时,对象本身会被隐式的传给方法的第一个参数。

point.my_print()
res = p1.distance(p2)
print(res)

输出:

(1,2)
2.8284271247461903

因此,定义对象方法会习惯性的把第一个形参定义为self,表示调用对象本身

class Point:
    """
    表示平面坐标系中的一个点
    """
    name = '点'

    def my_print(self):
        print('({},{})'.format(self.x, self.y))

    def distance(self, p2):
        return ((self.x-p2.x)**2 + (self.y-p2.y)**2)**0.5

类方法

在类中通过装饰器classmethod来定义类方法。

调用类方法时,会把类自己作为第一个实参,就像一个实例方法把实例自己作为第一个实参。

案例:

定义一个类方法base_point用来返回坐标原点。

class Point:
    """
    表示平面坐标系中的一个点
    """
    name = '点'

    def my_print(self):
        print('({},{})'.format(self.x, self.y))

    def distance(self, p2):
        return ((self.x-p2.x)**2 + (self.y-p2.y)**2)**0.5
    
    @classmethod
    def base_point(cls):
        bp = cls()
        bp.x = 0
        bp.y = 0
        return bp

通过类本身或者是该类的实例都可以调用类方法。

p = Point()
bp1 = p.base_point()
bp1.my_print()
bp2 = Point.base_point()
bp2.my_print()

输出:

(0,0)
(0,0)

特殊方法(魔术方法)

在类中可以定义一些特殊的方法用来实现特殊的功能,也称为魔术方法。这些方法一般都以双下划线__开头。

__init__

__init__又叫构造方法,初始化方法,在调用类名实例化对象时,构造方法会被调用,类名括号()后的参数会传递给构造方法,对象属性一般在这个方法中定义。

案例:

上面案例中的Point类实例化后,需要手动创建对象属性xy,这显然容易出错和不规范,正确的做法应该是在构造方法中定义属性xy

class Point:
    """
    表示平面坐标系中的一个点
    """
    name = '点'
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def my_print(self):
        print('({},{})'.format(self.x, self.y))

    def distance(self, p2):
        return ((self.x-p2.x)**2 + (self.y-p2.y)**2)**0.5
    
    @classmethod
    def base_point(cls):
        return cls(0,0)

# 实例化
p1 = Point(1, 2)			# 实例化时传递参数给构造方法
p2 = Point(x=3, y=4)

p1.my_print()
p2.my_print()

输出:

(1,2)
(3,4)

__str__

__str__方法在对象被print函数打印时被调用,print输出__str__方法返回的字符串。

案例:

上面案例中Point类里的my_print方法可以去掉,定义一个__str__方法

class Point:
    """
    表示平面坐标系中的一个点
    """
    name = '点'
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __str__(self):
        return '({},{})'.format(self.x, self.y)

    def distance(self, p2):
        return ((self.x-p2.x)**2 + (self.y-p2.y)**2)**0.5
    
    @classmethod
    def base_point(cls):
        return cls(0,0)
p = Point(2,2)
print(p)

输出:

(2,2)

更多的特殊方法详见官方文档

建议初学者,暂时学习这两个方法就够了。

静态方法

在类中通过装饰器staticmethod定义静态方法。

静态方法不会接收隐式的第一个参数,它和普通的函数一样,只是被封装到类中。

通过类和对象都可以调用。

案例:

在Point类中定义一个静态方法,用来计算两个数的和。

class Point:
    """
    表示平面坐标系中的一个点
    """
    name = '点'
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __str__(self):
        return '({},{})'.format(self.x, self.y)

    def distance(self, p2):
        return ((self.x-p2.x)**2 + (self.y-p2.y)**2)**0.5
    
    @classmethod
    def base_point(cls):
        return cls(0,0)
    
    @staticmethod
    def sum(x,y):
        return x+y
Point.sum(1,2)

p = Point(1,2)
p.sum(3,4)

输出:

3
7

总结:

当某个函数和对象相关时,这个函数就可以定义为对象方法。

当某个函数和类相关时,这个函数就可以定义为类方法。

某个函数跟类和对象都不相关,但是又想通过类和对象去调用时,就可以定义为静态方法。

posted @ 2022-08-29 14:01  python心蓝  阅读(53)  评论(0编辑  收藏  举报