1. 程式人生 > 實用技巧 >Python第六天-面向物件

Python第六天-面向物件

使用函式模擬定義類

def Person(name, age):
    def run(self):
        print("{name} is running".format(name=self["name"]))

    def init():
        return {
            "name": name,
            "age": age,
            "run": run
        }

    return init()


# 模擬建立一個物件
lisi = Person("lisi", 24)
# 模擬呼叫物件的方法
lisi["run"](lisi)

定義類

class Person():
    def __init__(self, name):
        self.name = name

    def run(self):
        print("{} is running".format(self.name))


xiaoming = Person("xiaoming")
xiaoming.run()

使用class 宣告類,預設繼承object類,例項化物件是預設呼叫__init__方法,xiaoming.run() 就類似於 Person.run(xiaoming),self引數就是的當前物件。

物件屬性和類屬性

class Person(object):
    NAME = "lisi"

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

    def run(self):
        print("{} is running".format(self.name))

    def of():
        return Person(Person.NAME)


xiaoming = Person("xiaoming")
xiaoming.run()

print(Person.NAME)
print(Person.__dict__)
print(Person.of().__dict__)

name屬性為物件屬性,NAME為類屬性,函式都是類的屬性,當物件呼叫函式時,在當前物件中找不到這個屬性函式,會去類中找,相當於當前作用域和上級作用域的關係。

物件方法,類方法,靜態方法

class Circular():
    PI = 3.14

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

    @property
    def perimeter(self):
        return 2 * self.PI * self.radius

    def calcPerimeter(self):
        return 2 * self.PI * self.radius

    @staticmethod
    def calcArea(radius):
        return Circular.PI * radius * radius

    @classmethod
    def area(cls, radius):
        return cls.PI * radius * radius


circular = Circular(2)
print(circular.perimeter)
print(circular.calcPerimeter())
print(Circular.calcArea(2))
print(Circular.area(2))

@property將方法裝飾為一個屬性,@staticmethod表示靜態方法,通過類呼叫,@classmethod表示類方法,也通過類呼叫

類繼承

import abc

class Runnable(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def run(self):
        pass


class Cat(Runnable):

    def run(self):
        print("Cat is running...")


class Dog(Runnable):

    def run(self):
        print("Dog is running...")


cat = Cat()
cat.run()
dog = Dog()
dog.run()

定義一個類似於java中介面的父類,並且將方法定義為抽象方法,這個子類就必須重寫這些方法。

類的內建方法

class Animal():
    """
    類的內建方法
    """

    """
    訪問屬性首先會呼叫本方法,會檢測__dict__中是否包含屬性 print(obj.item)
    """

    def __getattribute__(self, item):
        return super().__getattribute__(item)

    """
    呼叫__getattribute__方法沒有獲取到時呼叫,print(obj.item)
    """

    def __getattr__(self, item):
        return "default"

    """
    設定物件屬性時呼叫,obj.key=value
    """

    def __setattr__(self, key, value):
        return super().__setattr__(key, value)

    """
    刪除物件屬性時呼叫 del obj.item
    """

    def __delattr__(self, item):
        return super().__delattr__(item)

"""
    以obj[item]方式訪問屬性時被呼叫
    """

    def __getitem__(self, item):
        return self.__getattribute__(item)

    """
    obj[item] = value
    """

    def __setitem__(self, key, value):
        self.__setattr__(key, value)

    """
    del obj[item]
    """

    def __delitem__(self, key):
        self.__delattr__(key)

    """
    str(obj)被呼叫 返回物件的字串形式
    """

    def __str__(self):
        return "this is Animal"

    """
    repr(obj)被呼叫 類似__str__ 控制檯列印
    """

    def __repr__(self):
        return self.__str__()

    """
    len(obj)被呼叫
    """

    def __len__(self):
        return len(self.__str__())

    """
    format(obj)被呼叫
    """

    def __format__(self, format_spec):
        return "this is Animal"

    """
    手動del obj或被gc回收時被呼叫
    """

    def __del__(self):
        print("del")
        pass

    """
    obj()被呼叫
    """

    def __call__(self, *args, **kwargs):
        pass

    """
    next(obj)被呼叫,返回迭代器的下一個元素
    """

    def __next__(self):
        pass

    """
    iter(obj)被呼叫,返回一個迭代器物件
    """

    def __iter__(self):
        return iter([])
class Person():
    __slots__ = ["name", "age"]

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


p = Person("lisi", 23)
p.pwd = "as"
print(p.pwd)

定義了__slots__屬性,物件就沒有__dict__屬性了,就限制了物件的屬性字典,不能增加新的屬性。

描述符

class Desc():

    def __set__(self, instance, value):
        print("set")

    def __get__(self, instance, owner):
        print("get")

    def __delete__(self, instance):
        print("del")

一個類定義了以上3個方法任意一個就是一個描述符,只定義get為非資料描述符,定義了set,del為資料描述符

class TestDesc():
    desc = Desc()


test_desc = TestDesc()
test_desc.desc = "a"
print(test_desc.desc)

描述符必須定義為類屬性,當呼叫test_desc.desc = "a"時,實際上會轉換成TestDesc.dict['desc '].get(test_desc, TestDesc)

屬性查詢優先順序總結

  1. getattribute(), 無條件呼叫

  2. 資料描述符:由 ① 觸發呼叫 (若人為的過載了該 getattribute() 方法,可能會導致無法呼叫描述符)

  3. 例項物件的字典(若與描述符物件同名,會被覆蓋)

  4. 類的字典

  5. 非資料描述符

  6. 父類的字典

  7. getattr() 方法