python类的实例方法、静态方法、类方法、属性方法(property)

481 阅读6分钟

语法

实例方法:

​ 第一个参数必须要默认传实例对象,一般用self,代表实例本身

​ 只能被实例对象调用

静态方法:

​ 用@staticmethod装饰,参数没有要求

​ 可以被类或类的对象(即实例)调用

【跟类有关,但实现时并不需要引用类或者实例,如设置环境变量、修改另一个类的变量等】

类方法:

​ 用@classmethod装饰,第一个参数必须默认传类,一般用cls,代表类本身

​ 可以被类或类对象(即实例)调用

【当一个方法中只涉及到静态属性的时候可以使用类方法(类方法用来修改类属性)】

class Foo(object):
    """类三种方法语法形式"""

    def instance_method(self):#self表示实例本身
        print("是类{}的实例方法,只能被实例对象调用".format(Foo))

    @staticmethod
    def static_method():
        print("是静态方法")

    @classmethod
    def class_method(cls):#cls表示类本身
        print("是类方法")

print('--------实例调用--------')
foo = Foo()
foo.instance_method()
foo.static_method()
foo.class_method()
print('--------类调用--------')
# Foo.instance_method() #报错
Foo.static_method()
Foo.class_method()

运行结果如下

--------实例调用--------
是类<class '__main__.Foo'>的实例方法,只能被实例对象调用
是静态方法
是类方法
--------类调用--------
是静态方法
是类方法

使用区别和说明场景

类方法用于模拟java中定义多个构造函数的情况

python类中只能有一个初始方法,不能按照不同的类型初始化类

class Book(object):

    def __init__(self, title):#构造函数
        self.title = title

    @classmethod
    def class_method_create(cls, title):
        book = cls(title=title)
        return book

    @staticmethod
    def static_method_create(title):
        book = Book(title)#静态方法需要用类名调用
        return book


book1 = Book("use instance_method_create book instance")
book2 = Book.class_method_create("use class_method_create book instance")
book3 = Book.static_method_create("use static_method_create book instance")
print(book1.title)
print(book2.title)
print(book3.title)

运行结果如下

use instance_method_create book instance
use class_method_create book instance
use static_method_create book instance

静态方法调用静态方法&类方法调用静态方法

class Foo(object):
    X = 1
    Y = 2

    @staticmethod
    def averag(*mixes):
        return sum(mixes) / len(mixes)

    @staticmethod
    def static_method():  # 在静态方法中调用静态方法
        print
        "在静态方法中调用静态方法"
        return Foo.averag(Foo.X, Foo.Y)

    @classmethod
    def class_method(cls):  # 在类方法中使用静态方法
        print
        "在类方法中使用静态方法"
        return cls.averag(cls.X, cls.Y)  #用cls代替类调用,代码更简洁


foo = Foo()
print("-------静态方法调用静态方法--------")
print(foo.static_method())
print("-------类方法调用静态方法--------")
print(foo.class_method())

运行结果如下

-------静态方法调用静态方法--------
1.5
-------类方法调用静态方法--------
1.5

继承的区别

子类覆盖父类的静态方法averag:

(1)子类调用static_method方法,调用的还是父类的方法和属性

(2)子类调用class_method方法,调用的是子类的方法和属性

子类不覆盖父类的averag:

(1)子类调用static_method方法,调用的是父类的方法和属性

(2)子类调用class_method方法,调用的是父类的方法和子类的属性

'''
子类覆盖父类的静态方法averag:

(1)子类调用static_method方法,调用的还是父类的方法和属性

(2)子类调用class_method方法,调用的是子类的方法和属性
'''
class Foo(object):
    X = 1
    Y = 14

    @staticmethod
    def averag(*mixes):  # "父类中的静态方法"
        print("Foo的averag方法 ", mixes)
        return sum(mixes) / len(mixes)

    @staticmethod
    def static_method():  # "父类中的静态方法"
        print("父类中的静态方法")
        return Foo.averag(Foo.X, Foo.Y)

    @classmethod
    def class_method(cls):  # 父类中的类方法
        print("父类中的类方法")
        return cls.averag(cls.X, cls.Y)

class Son(Foo):
    X = 3
    Y = 5

    @staticmethod
    def averag(*mixes):  # "子类中重载了父类的静态方法"
        print("子类中重载了父类的静态方法")
        print("son的averag方法 ", mixes)
        return sum(mixes) / 3

p = Son()
print("------result of p.averag(1,5)------")
print(p.averag(1, 5))
print("------result of p.static_method()--------")
print(p.static_method())
print("------result of p.class_method()------")
print(p.class_method())

运行结果如下

------result of p.averag(1,5)------
子类中重载了父类的静态方法
son的averag方法  (1, 5)
2.0
------result of p.static_method()--------
父类中的静态方法
Foo的averag方法  (1, 14)
7.5
------result of p.class_method()------
父类中的类方法
子类中重载了父类的静态方法
son的averag方法  (3, 5)
2.6666666666666665
'''
子类不覆盖父类的averag:

(1)子类调用static_method方法,调用的是父类的方法和属性

(2)子类调用class_method方法,调用的是父类的方法和子类的属性
'''
class Foo(object):
    X = 1
    Y = 14

    def averag(self,*mixes):
        self.mixes=mixes
        print("Foo的averag方法 ", self.mixes)
        return sum(self.mixes) / len(self.mixes)

    @staticmethod
    def static_method():  # "父类中的静态方法"
        print("父类中的静态方法")
        return Foo().averag(Foo.X, Foo.Y) #调用实例方法用实例调用。Foo是类,Foo()是实例

    @classmethod
    def class_method(cls):  # 父类中的类方法
        print("父类中的类方法")
        return cls().averag(cls.X, cls.Y)#调用实例方法用实例调用。cls是类,cls()是实例

class Son(Foo):
    X = 3
    Y = 5

p = Son()
print("------result of p.averag(1,5)------")
print(p.averag(1, 5))
print("------result of p.static_method()--------")
print(p.static_method())
print("------result of p.class_method()------")
print(p.class_method())

运行结果:

------result of p.averag(1,5)------
Foo的averag方法  (1, 5)
3.0
------result of p.static_method()--------
父类中的静态方法
Foo的averag方法  (1, 14)
7.5
------result of p.class_method()------
父类中的类方法
Foo的averag方法  (3, 5)
4.0

属性方法(property)

可以称作属性方法,可以修改参数,但是不能随意修改

方法一:绑定属性,属性直接暴露,可以随意修改属性值,未做校验

class Student(object):
    pass

s=Student()
s.score='abc'
print(s.score)

运行结果:

abc

方法二:通过set_score()检查参数,通过get_score()获取参数;此方法调用较复杂

class Student(object):
    def get_score(self):
        return self._score
    def set_score(self,value):
        if not isinstance(value,int):
            raise ValueError('score must be an integer!')
        if value<0 or value >100:
            raise ValueError('score must between 0~100!')
        self._score=value

s=Student()
s.set_score(100)
print(s.get_score())
s.set_score('abc')
print(s.get_score())

运行结果:

Traceback (most recent call last):
  File "E:/learning/proexe/main.py", line 14, in <module>
    s.set_score('abc')
  File "E:/learning/proexe/main.py", line 6, in set_score
    raise ValueError('score must be an integer!')
ValueError: score must be an integer!
100

方法三:python内置的@property装饰器可以实现上述功能,且调用方法简单

方法二与方法三中,get/set函数名一样,分别多了装饰器@property和@score.setter

@property 加了这个装饰器的func相当于getfunc()

@score.setter加了这个装饰器的func相当于setfunc

class Student(object):
    @property
    def score(self):
        return self._score
    @score.setter
    def score(self,value):
        if not isinstance(value,int):
            raise ValueError('score must be an integer!')
        if value<0 or value >100:
            raise ValueError('score must between 0~100!')
        self._score=value

s=Student()
s.score=99
print(s.score)
s.score=101
print(s.score)

运行结果:

99
Traceback (most recent call last):
  File "E:/learning/proexe/main.py", line 16, in <module>
    s.score=101
  File "E:/learning/proexe/main.py", line 10, in score
    raise ValueError('score must between 0~100!')
ValueError: score must between 0~100!

实现property属性的两种方式

补充一:python内置的@property装饰器用法补充

@property对应读取

@方法名.setter修改

@方法名.deleter删除属性

class Student:
    def __init__(self):
        self._score = 60

    @property
    def score(self):  # 读取
        return self._score

    # 方法名.setter
    @score.setter  # 设置,仅可接收除self外的一个参数
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0~100!')
        self._score = value

    # 方法名.deleter
    @score.deleter  # 删除
    def score(self):
        del self._score


# ############### 调用 ###############
obj = Student()  # 实例化对象
obj.score  # 直接获取 score属性值
obj.score = 90  # 修改score的值
print(obj.score)
del obj.score  # 删除score属性的值

补充二:类属性

当使用类属性的方式创建property属性时,property()方法有四个参数

第一个参数是方法名,调用 对象.属性 时自动触发执行方法

第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法

第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法

第四个参数是字符串,调用 对象.属性.doc ,此参数是该属性的描述信息

class Student(object):
    def __init__(self):
        self._score=60

    def get_score(self):
        return self._score

    def set_socre(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0~100!')
        self._score = value

    def del_score(self):
        del self._score

    # 获取    设置     删除    描述文档
    SCORE = property(get_score, set_socre, del_score, '属性描述...')

# 使用此方式设置
obj = Student()
obj.SCORE  # 获取score
obj.SCORE= 99  # 修改score
print(obj.SCORE)
del obj.SCORE  # 删除score