Python自定义类

私有属性获取与修改可以通过方法,这样可以在修改属性之前做些check。

class Student(object):
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    def getName(self):
        return self.__name

    def getScore(self):
        return self.__score

    def setName(self, name):
        self.__name = name

    def setScore(self, score):
        if score >= 0 and score <= 100:
            self.__score = score
        else:
            print("value wrong")
class Student(object):
    def __init__(self, name, score):
        self.__name = name
        self.__score = score

    @property
    def score(self):
        return self.__score

    @score.setter
    def score(self, value):
        if value >= 0 and value <= 100:
            self.__score = value
        else:
            print("value wrong")


s1 = Student("Andy", 90)

print(s1.score)

s1.score = 80

print(s1.score)

自定义类也称自定义数据类型,下面是自定义类的一些标识。

  • class
  • 类命名首字母大写
  • self
  • __init__

自定义类的语法

class CustomClass(object):
    pass

理解类的一些概念

  • 类封装
  • 类继承
  • 类多态
  • 实例属性和实例方法
  • 类属性和类方法
  • 静态方法
class MyClass(object):

    def __init__(self, var1, var2):
        self.a = var1
        self.b = var2

    def sum(self):
        return self.a + self.b

a = MyClass(200, 300)
print(a)
print(a.sum())

理解特殊方法__repr__,特殊方法也称魔法方法或者双下方法。

class Car(object):
    def __init__(self, name, eng, year):
        self.name = name
        self.eng = eng
        self.year = year

    def __repr__(self):
        return "My car name is %s" % self.name

car = Car("Jili", 120, 2019)
print(car)

类继承

class Car(object):
    def __init__(self, name, eng, year):
        self.name = name
        self.eng = eng
        self.year = year

    def __repr__(self):
        return "My car name is %s" % self.name

    def orderParts(self, *args):
        print("Connecting to server...")
        print("Ordering parts %s: for car %s" % (args, self.name))
        print("Checking status")

class Truck(Car):
    def __init__(self, name, eng, year):
        Car.__init__(self, name, eng, year)

truck = Truck("Benz", 800, 2008)
truck.orderParts("Wheels", "Silencer")

类继承分单继承和多继承,注意__init__的用法。

  • 如果子类没有定义初始化函数,父类的初始化函数默认被调用。
  • 如果子类定义了自己的初始化函数,但没有显示调用父类的初始化函数,则父类属性不会被初始化。
  • 如果子类定义了自己的初始化函数,在子类中显示调用父类,子类和父类的属性都会被初始化。

初始化方案

# python 2.x
def __init__(self, args):
    super(ClassName, self).__init__(args)

# python 3.x
def __init__(self, args):
    super().__init__(args)

def __init__(self, args):
    ClassName.__init__(args)

# PyQt中
# python 2.x
def __init__(self, parent=None):
    super(ClassName, self).__init__(parent)

# python 3.x
def __init__(self, parent=None):
    super().__init__(parent)

自定义向量类型

class Vector(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __repr__(self):
        return "Vector(%f, %f, %f)" % (self.x, self.y, self.z)

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

v1 = Vector(2, 1.5, 3.2)
v2 = Vector(3, 4, 5)
print(v1)
print(v1 + v2)
import math
from __future__ import division

class Vector(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z

    def __repr__(self):
        return "Vector(%f, %f, %f)" % (self.x, self.y, self.z)

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y, self.z + other.z)

    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y, self.z - other.z)

    def __mul__(self, other):
        return Vector(self.x * other.x, self.y * other.y, self.z * other.z)

    def __div__(self, other):
        return Vector(self.x / other.x, self.y / other.y, self.z / other.z)

    def __getitem__(self, item):
        if item == 0:
            return self.x
        elif item == 1:
            return self.y
        elif item == 2:
            return self.z
        else:
            raise IndexError("There is no vector index: %d" % item)

    def __setitem__(self, key, value):
        if key == 0:
            self.x = value
        elif key == 1:
            self.y = value
        elif key == 2:
            self.z = value
        else:
            raise IndexError("There is no vector index: %d" % key)

    def dot(self, other):
        return self.x * other.x + self.y * other.y + self.z * other.z

    def cross(self, other):
        return Vector(self.x * other.x, self.y * other.y, self.z * other.z)

    def length(self):
        return math.sqrt(pow(self.x, 2) + pow(self.y, 2) + pow(self.z, 2))

v1 = Vector(2, 1.5, 3.2)
v2 = Vector(3, 4, 5)
print(v1)
print(v1 + v2)
print(v1.dot(v2))
print(v1.length())
print(v1[2])
v1[2] = 10
print(v1)

实例方法、类方法和静态方法

import string

def getAllChars():
    all_letters = string.ascii_lowercase
    result=[]
    for letter in all_letters:
        result.append([letter, all_letters.find(letter)])
    return result

def generateChars():
    all_letters = string.ascii_lowercase
    for letter in all_letters:
        yield letter, all_letters.find(letter)

for i in generateChars():
    print("Letter: {0} - Index: {1}".format(*i))

语法糖与装饰器

  • @property
  • @classmethod
  • @staticmethod
def check_args(func):
    def wrap(*args):
        args = filter(bool, args)
        func(*args)

    return wrap


@check_args
def test(*args):
    print(args)


print(test)
test(1, 0, 2, "", [], 3)

装饰器不一定非得是个函数返回包装对象,也可以是个类,通过__call__完成目标调用

class CheckArgs(object):
    def __init__(self, func):
        self._func = func

    def __call__(self, *args):
        args = filter(bool, args)
        self._func(*args)


@CheckArgs
def test(*args):
    print(args)


print(test)
test(1, 0, 2, "", [], 3)

为class提供装饰器

def singleton(cls):
    def wrap(*args, **kwargs):
        o = getattr(cls, "__instance__", None)

        if not o:
            o = cls(*args, **kwargs)
            cls.__instance__ = o

        return o

    return wrap


@singleton
class A(object):
    def __init__(self, x):
        self.x = x

print(A)
a, b = A(1), A(2)
print(a is b)

类专属的装饰器

class Artist(object):
    _hits = ["John"]

    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):

        if name not in CUSTOM_ARTIST:
            raise ValueError("%s is not a custom artist" % name)

        self._name = name

    @staticmethod
    def random_artist():
        return Artist(random.choice(CUSTOM_ARTIST))

    @classmethod
    def hits(cls):
        return cls._hits


# rr = Artist("Andy Hu")
# print(rr.name)
# print(type(rr.name))
# rr.name = "Andy"
# print(rr.name)
# rr2 = Artist.random_artist()
# print(rr2.name)
# print(Artist.hits())
# print(Artist._hits)
rr = Artist("Andy")
print(rr.random_artist())
# print(rr.hits())

私有属性与私有方法

在定义方法前面加__method即声明私有方法,理论上私有方法是不能被继承的,只能在当下定义的类中被调用,但Python的私有方法只是约定上的私有,实际是可以通过类名来访问。

  • 类属性和类方法可以被实例对象来调用,也可以通过类名直接调用,一般是通过类名调用
  • 静态方法可以被实例对象来调用
  • 实例属性和实例方法只能通过实例对象来调用,不能通过类名直接调用
  • 静态方法和类方法的区别是类方法可能需要访问类属性,和类还有那么点关系,静态方法是访问不了任何类属性或者实例属性的