30.Python面向对象类方法和静态方法动态绑定属性和__slots__限制绑定@property

Posted 孤寒者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了30.Python面向对象类方法和静态方法动态绑定属性和__slots__限制绑定@property相关的知识,希望对你有一定的参考价值。

目录:

每篇前言:


Python面向对象(三)

1.1 类方法和静态方法

1.1.1 类方法

  • 是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以’cls’作为第一个参数的名字,就最好用’cls’了),能够通过实例对象和类对象去访问。
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class People(object):
    country = 'china'

    #类方法,用classmethod来进行修饰
    @classmethod
    def getCountry(cls):
        return cls.country

p = People()
print(p.getCountry())    #可以用过实例对象引用
print(People.getCountry())    #可以通过类对象引用

  • 类方法还有一个用途就是可以对类属性进行修改:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class People:
    country = 'china'

    #类方法,用classmethod来进行修饰
    @classmethod
    def getCountry(cls):
        return cls.country

    @classmethod
    def setCountry(cls,country):
        cls.country = country


p = People()
print(p.getCountry())    #可以用过实例对象引用
print(People.getCountry())    #可以通过类对象引用

p.setCountry('japan')

print(p.getCountry())
print(People.getCountry())

  • 结果显示在用类方法对类属性修改之后,通过类对象和实例对象访问都发生了改变。

1.1.2 静态方法

需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数。

# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class People:
    country = 'china'

    # 静态方法
    @staticmethod
    def getCountry():
        return People.country

print(People.getCountry())

1.1.3 总结

从类方法和实例方法以及静态方法的定义形式就可以看出来,类方法的第一个参数是类对象cls,那么通过cls引用的必定是类对象的属性和方法;而实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可能是实例属性(这个需要具体分析),不过在存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。静态方法中不需要额外定义参数,因此在静态方法中引用类属性的话,必须通过类对象来引用

2.1 动态绑定与限制

2.1.1 动态绑定属性

# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Student(object):
    pass

s = Student()
s.name = 'Michael'  # 动态给实例绑定一个属性

def set_age(self, age):  # 定义一个函数作为实例方法
    self.age = age

from types import MethodType

s.set_age = MethodType(set_age, s)  # 给实例绑定一个方法
s.set_age(25)  # 调用实例方法
print(s.age)  # 测试结果

但是,给一个实例绑定的方法,对另一个实例是不起作用的:

s2 = Student() # 创建新的实例
s2.set_age(25)
Traceback (most recent call last):
  File "D:/******/test.py", line 17, in <module>
    s2.set_age(25)
AttributeError: 'Student' object has no attribute 'set_age'

为了给所有实例都绑定方法,可以给class绑定方法:

def set_score(self, score):
    self.score = score
Student.set_score = MethodType(set_score, Student)

给class绑定方法后,所有实例均可调用:

s.set_score(100)
print(s.score)
s2 = Student()
s2.set_score(99)
print(s2.score)

通常情况下,上面的set_score方法可以直接定义在class中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。

2.1.2 __slots__ 限制绑定

  • 如果我们想要限制class的属性,比如只允许对Student实例添加name和age属性。
  • 为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class能添加的属性:
class Student(object):
    __slots__ = ('name', 'age')
  • 然后,我们就试试:
s = Student() # 创建新的实例
s.name = 'xiaoming' # 绑定属性'name'
s.age = 25 # 绑定属性'age'
s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
  • 由于’score’没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。
  • 使用__slots__要注意,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的:
    除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__

3.1 使用@property将方法变成属性调用

语法:

  • class property([fget[, fset[, fdel[, doc]]]])

参数:

  • fget – 获取属性值的函数
  • fset – 设置属性值的函数
  • fdel – 删除属性值函数
  • doc – 属性描述信息

返回新式类属性。
将 property 函数用作装饰器可以很方便的创建只读属性:

# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Parrot(object):
    def __init__(self):
        self._voltage = 100000

    @property
    def voltage(self):
        """Get the current voltage."""
        return self._voltage
  • 上面的代码将 voltage() 方法转化成同名只读属性的 getter 方法。
  • property 的 getter,setter 和 deleter 方法同样可以用作装饰器:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

3.2 mro算法

  • mro顺序/算法,目的是保证程序能够按序执行。

mro顺序的作用:

  • 保证所有的类在用(构造)他的时候只被用(构造)一次!
    保证多继承的时候,每个类只出现一次。
    super().__init__() 相当于使用了mro。

前面说要讲,但是在基础阶段如果深入讲的话,我怕大家一时接受不了,所以就先这样浅显有个认识即可!有机会我会细讲。

以上是关于30.Python面向对象类方法和静态方法动态绑定属性和__slots__限制绑定@property的主要内容,如果未能解决你的问题,请参考以下文章

30.Python面向对象类方法和静态方法动态绑定属性和__slots__限制绑定@property

Scala核心编程_第08章 面向对象编程(中级补充)--java动态绑定与静态绑定

Scala核心编程_第08章 面向对象编程(中级补充)--java动态绑定与静态绑定

面向对象之多态

面向对象编程——类方法和静态方法

Java多态之动态绑定