オブジェクト指向の多型のpython - ビルトインクラス関連の機能 - クラス組み込みマジック機能 - イテレータプロトコル - コンテキスト管理を-04

ポリモーフィズム

異なる形のあるもの

例えば:水 - >固体、液体、気体

ポリモーフィック:# 多个不同对象可以相应同一个对象,产生不同的结果

まず強調、多型は、特別な構文ではなく、状態、特性(異なるオブジェクトの対応する複数の同様の方法、本体の長さの異なる結果であってもよいです)

利点:ユーザーのために、コスト削減の使用

以前のUSBインタフェース、マウス、キーボードの下で、彼らは多状態です

インタフェース型は、抽象クラスは(アヒル最も単純なタイプ)の多型を含むコードを書くことができアヒル

'''
要管理 鸡 鸭 鹅
    如何能够最方便的管理,就是我说同一句话,他们都能理解
    他们拥有相同的方法
'''


class Chicken:
    @staticmethod
    def bark():
        print("咯咯咯咯")

    @staticmethod
    def spawn():
        print("下鸡蛋...")


class Duck:
    @staticmethod
    def bark():
        print("嘎嘎嘎")

    @staticmethod
    def spawn():
        print("下鸭蛋...")


class E:
    @staticmethod
    def bark():
        print("鹅鹅鹅鹅")

    @staticmethod
    def spawn():
        print("下鹅蛋...")


j = Chicken()
y = Duck()
e = E()


def mange(obj):
    obj.spawn()


mange(j)
# 下鸡蛋...
mange(y)
# 下鸭蛋...
mange(e)
# 下鹅蛋...

Pythonの共通多型(同じメソッドで異なるオブジェクトタイプ、異なる結果)

# 不管什么类型,他都与type这个方法  ---> python中多态的体现
# 多态在python中其实很常见,因为到处充斥着继承与组合
a = 10
b = '10'
c = [10]

print(type(a))
print(type(b))
print(type(c))
# <class 'int'>
# <class 'str'>
# <class 'list'>

一般的な組み込み関数

  • isinstance
 # isinstance()  # 判断一个对象是不是某个类的实例
 # 参数1 要判断的对象,参数2 要判断的类型 
def add_num(a, b):
    # if type(a) == type(b):
    if isinstance(a, int) == isinstance(b, int):
        return a+b
    else:
        print("数据类型不符")


add_num("100", 10)
  • issubclass
# issubclass() # 判断一个类是不是另一个类的子类
#   参数一:子类,参数二:父类
class Animal:
    @staticmethod
    def eat():
        print("动物得吃东西...")


class Pig(Animal):
    @staticmethod
    def eat():
        print("猪吃东西...")


class Tree:
    @staticmethod
    def light():
        print("植物光合作用...")


def mange(obj):
    # if isinstance(obj, Animal):
    if issubclass(type(obj), Animal):
        obj.eat()
    else:
        print("不是动物...")


pig = Pig()
t = Tree
mange(pig)
# 猪吃东西...
mange(Tree)  # AttributeError: type object 'Tree' has no attribute 'eat'
# 不是动物...

オブジェクト指向の機能が内蔵された魔法

  • __str__
'''
    __str__ 会在对象被转为字符串时,转换的结果就是这个函数的返回值
    使用场景:我们可以利用该函数来自定义,对象是打印格式
'''
class Person:
    def __str__(self):  # 重写object中的 __str__
        print("__str__ run")
        return 'abc'  # abc下面的报错那里就变成了 abc


p = Person()
# 所有的类都可以转成字符串
print(p)  # 打印了 __str__ run,又报错了
# __str__ run
# abc  # 写return 之前TypeError: __str__ returned non-string (type NoneType)  --> __str__ 必须要有一个str类型的返回值

str(p)  # 没有写print 在控制台也输出了 __str__ run
# __str__ run

オブジェクト指定された出力形式

# print打印对象时内存地址,没什么意义,此时就可以利用__str__来自定义对象打印
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):  # 重写object中的 __str__
        return f"这是要给Person对象,name:{self.name},age:{self.age}"


p = Person('jack', 10)
# 所有的类都可以转成字符串
print(p)  # 打印了
# 这是要给Person对象,name:jack,age:10
  • __del__
# del 析构函数   (__init__ 构造函数)
# 执行时机:手动删除对象时立马执行,或是程序运行结束时也会自动执行(垃圾回收机制?)
# 使用场景:当你的对象再使用过程中打开了不属于解释器的资源,例如文件,网络端口
import time


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

    def __del__(self):  # 重写object中的 __str__
        print("del run...")
        return "del run"


p = Person("jack", 20)
# del p  # 删除对象触发 __del__函数执行
# # del run...
time.sleep(2)
print("over")
# over
# del run...  # 程序结束后会把名称空间清除掉,清除时触发了 __del__,打印出 del run...

自動的にファイルケースを閉じ、リソースの使用を終了

class FileTool:
    # 该类用于简化文件的读写操作

    def __init__(self, path):
        self.file = open(path, 'rt', encoding='utf-8')

    def read(self):
        return self.file.read()  # rt模式不推荐直接读字节(汉字、英文字节不同),可以一行一行读

    # 执行这个函数可以确定一个函数,这个对象肯定不用了,所以就可以放心的关心文件了
    def __del__(self):
        self.file.close()


tool = FileTool("a.txt")
print(tool.read())  # 文件属于操作系统,不受垃圾回收机制管理
# aaaaaaaaaaaa

# 不知道什么不使用该对象,那就写在 __del__函数中,当其被删除时,指定关闭资源
  • __call__
# call  调用对象时自动执行
# 执行时机:在调用对象时自动执行 ---> 对象()


class A:
    # 调用对象时自动执行
    def __call__(self, *args, **kwargs):
        print("__call__ run...")
        print(args)
        print(kwargs)


a = A()

a(1, 2, a=100, c=300)  # 对象加括号调用
# __call__ run...
# (1, 2)
# {'a': 100, 'c': 300}
  • __slots__

Pythonは動的言語され、あなたが動的にどのように多くの属性を格納することができ、実行時にオブジェクトのプロパティを変更できますか?
より大きなメモリ領域を開く必要があり、元のプロパティの割り当ての最後の
質問:(スペースを犠牲にして効率のために)あまりにも多くの容量を有効にした場合、廃棄物のメモリが発生します
解決策を:システムオブジェクトを作成するだけでどのプロパティを伝えるすることを目的とします、それは、オブジェクトの固定プロパティの数ですので、あなたは、無駄なスペースを削減する方法について多くの任意の数(使用を開くことができます__slots__

import sys


class Person:
    __slots__ = ['name']  # 加了以后再添加属性就不行了,限制属性

    # def __init__(self, name, age):
    def __init__(self, name):
        self.name = name
        # self.age = age  # 未在__slots__中声明,直接报错 AttributeError: 'Person' object has no attribute 'age'


# p = Person("jck", 18)
p = Person("jck")

print(sys.getsizeof(p))  # 获取对象占用内存大小
# 56 ---> 48  ---> __slots__ 指定有哪些属性,从而节省了内存空间(没指定__slots__之前56,指定之后48)

# print(p.__dict__)  # 报错,可变字典也被省掉了(名称空间连开都不开了),AttributeError: 'Person' object has no attribute '__dict__'

このプロパティは、メモリオブジェクトを最適化するためのクラス属性であります

最適化された原則:インタプリタは、オブジェクトに名前空間を(それが作成されないように、元の属性の固定数ではありませんが、それは、固定となり__dict__、メモリのオーバーヘッドを低減する効果を達成するように、またしませんでした)

クラスがある場合にも__slots__、このクラスのオブジェクトが追加につながることはありません時に__slots__定義された以外の属性

  • __getattr__ __setattr__ __delattr__ 及点语法原理
__getattr__ 用 .访问属性时,如果属性不存在,执行
__setattr__ 用 .设置属性时执行
__delattr__ 用del 对象.属性 删除属性时,执行

这几个函数反映了 python解释器是如何实现 . 语法的原理

__getattribute__ 该函数也是用来获取属性
在获取属性时如果存在__getattribute__则先执行该函数,如果没有拿到属性则继续调用__getattr__函数,如果拿到了则直接返回
class A:
    def __getattr__(self, item):
        print("__getattr__")
        return self.__dict__.get(item)

    def __setattr__(self, key, value):
        super().__setattr__(key, value)  # 这个不写将导致赋值不成功,得到None
        print('__setattr__')

    def __delattr__(self, item):
        print('__delattr__')
        print(item)
        self.__dict__.pop(item)


a = A()
a.name = 'jack'
# __setattr__
print(a.name)  # 这个属性存在,就没有调用 __getattr__
# jack


b = A()
b.__dict__["name"] = 'jackson'  # 通过操作__dict__ 也可以操作属性(. 语法的背后就是操作 __dict__)
print(b.name)  # 这个属性存在,就没有调用 __getattr__
# jackson

del b.name  # 触发 __delattr__
# __delattr__
# name

print(b.name)  # b没有name这个属性了,就触发了 __getattr__
# __getattr__
# None  # b没有name这个属性了
class B:
    def __setattr__(self, key, value):  # 利用了 .语法赋值改值就会触发这个函数
        self.__dict__[key] = value
        print(f"{key}:{value}")


b = B()
b.name = 'jerry'
# name:jerry
b.name = 'tom'
# name:tom
print(b.name)
# tom

b.__dict__['halo'] = 'hi'  # 直接通过操作 __dict__ 也可以完成属性的增改
print(b.halo)
# hi
  • []実現原理__getitem__ __setitem__ __delitem__()

任意の記号、インタプリタは、[]()は、例えば、その特別な意味を説明します

__getitem__ 当你用中括号去获取属性时 执行
__setitem__ 当你用中括号去设置属性时 执行
__detitem__ 当你用中括号去删除属性时 执行

'''
需求:
    让一个对象支持 点语法来取值,也支持括号取值
'''


class MyDict(dict):
    def __getattr__(self, key):
        return self.get(key)
        # return self[key]  # KeyError: 'name'

    def __setattr__(self, key, value):
        self[key] = value

    def __delattr__(self, item):
        del self[item]


# 继承 dict 可以直接用字典的一些方式
a = MyDict()
a['name'] = 'jack'
print(a['name'])
# jack

# 使用 .语法(通过实现__getattr__ 、__setattr__、__delattr__来实现)
a.name = 'sum'
print(a.name, a['name'])
# sum sum
print(a['name'])
# sum
a.name = 'jackson'
print(a.name)
# jackson
del a.name
print(a.name)
# None  # 用的是 .get 所以不会报错
  • > >= == != < <=などの比較演算子(演算子のオーバーロード)の原則を達成するために(__gt__ __ge__ __eq__ __ne__ __lt__ __le__

私たちは、特定の記号を使用すると、Pythonインタプリタは、の意味のためのシンボル定義になり、私たちは、カスタムオブジェクトの比較規則に必要がある場合、対応するハンドラを呼び出すなど以上のサブクラスのメソッドをカバーすることができます

ケース

# 自定义对象的比较
# 对象直接无法直接比较大小


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


p1 = Person('jason', 185, 18)
p2 = Person('tank', 179, 18)
# print(p1 > p2)  # TypeError: '>' not supported between instances of 'Person' and 'Person'


class Student:
    def __init__(self, name, height, age):
        self.name = name
        self.height = height
        self.age = age

    # 自定义比较规则
    def __gt__(self, other):
        print(self)
        print(other)
        print("__gt__")

        # 比身高
        # if self.height > other.height:
        #     return True
        return self.height > other.height
        # 没有返回值默认返回 None 即 False

    def __eq__(self, other):
        print("eq------")
        return self.name == other.name


stu1 = Student("jack", 180, 28)
stu2 = Student("rose", 165, 27)

print(stu1 > stu2)  # 直接报错,TypeError: '>' not supported between instances of 'Student' and 'Student'
# <__main__.Student object at 0x000001992C7C8F60>
# <__main__.Student object at 0x000001992C7C8F98>
# __gt__
# True
print(stu1 < stu2)  # 大于和小于只要实现一个即可,符号如果不同解释器会自动交换两个对象的位置
# <__main__.Student object at 0x000001992C7C8F98>
# <__main__.Student object at 0x000001992C7C8F60>
# __gt__
# False
print(stu1)
# <__main__.Student object at 0x000001992C7C8F60>
print(stu2)
# <__main__.Student object at 0x000001992C7C8F98>

もともとカスタムオブジェクトを比較するよりも、より少ない直接大きい使用することはできない、我々は達成するためにオペレータをカスタマイズすることができ、また、カスタムオブジェクトは比較演算子をサポートします

上記.OTHERコードは、他の参加の比較の対象を指し

上記および下記のもののいずれかでき、異なるシンボルインタプリタは自動的に二つのオブジェクトの位置を切り替える場合

イテレータプロトコル

イテレータ:それはいい__iter____next__オブジェクト

私たちはするオブジェクトのためにこれらの2つのメソッドを追加することができ、オブジェクトがイテレータになり作ります

class MyIter:
    # num 传入,用来指定迭代次数
    def __init__(self, num):
        self.num = num
        self.c = 0

    def __iter__(self):
        return self

    def __next__(self):
        self.c += 1
        if self.c <= self.num:
            return "hahha"
        raise StopIteration  # 抛出异常


for i in MyIter(3):
    print(i)
# hahha
# hahha
# hahha

カスタムレンジ機能

class MyRange:
    def __init__(self, start, end, step=1):
        self.start = start - 1
        self.end = end
        self.step = step

    def __iter__(self):
        return self

    def __next__(self):
        self.start += self.step
        if self.start < self.end:
            return self.start
        raise StopIteration


for i in MyRange(1, 3):
    print(i)
# 1
# 2

コンテキスト管理

コンテキスト:この概念は、現在のシーンにそのコンテキストを参照するために、通路の意味を参照して、語学学習に属し

Pythonでは、コンテキストは次のように理解することができるコードのセクションの範囲この文脈でオープンのみ有効で、例えば、開いているファイルを

方法は、2つのコンテキストを含みます

  • __enter__:(のシーンを入力してください)コンテキストを入力することを示します

  • __exit__:(のシーンを残して)、出口コンテキストを意味します

ケース

class MyOpen:

    def __enter__(self):
        print("enter....")

    def __exit__(self, exc_type, exc_val, exc_tb):  # exc --> exception
        print("exit.....")
        print(exc_type, exc_val, exc_tb)


with MyOpen() as m:
    print("start...")
    # 1 + '123'
# enter....
# exit.....
# None None None

文を使用して実行されたときに上記2つの方法がステートメントと一緒に使用することができる達成するために、最初に実行される__enter__コードが実行を完了すると、__exit__コードまたは例外が発生したすぐに実行される__exit__エラーメッセージを渡し、エラーを含みますタイプ、誤った情報、エラー追跡情報

class MyOpen:

    def __enter__(self):
        print("enter....")

    def __exit__(self, exc_type, exc_val, exc_tb):  # exc --> exception
        print("exit.....")
        print(exc_type, exc_val, exc_tb)
        return True  # return True 可以让程序不报错


with MyOpen() as m:
    print("start...")
    1 + '123'  # TypeError: unsupported operand type(s) for +: 'int' and 'str'
# enter....
# exit.....
# None None None  # 没有报错时打印这个
# <class 'TypeError'> unsupported operand type(s) for +: 'int' and 'str' <traceback object at 0x00000283F3EE0608>  # 有错时打印这个,若__exit__ 返回为True则控制台不报错,否则控制台也会报错

注意点

__enter__ 函数应该返回对象自己
__exit__ 函数可以有返回值,是一个bool类型,用于表示异常是否被处理,仅在上下文中出现异常时有用
如果为True 则意味着,异常已经被处理了
    False 异常未被处理,程序将中断报错

おすすめ

転載: www.cnblogs.com/suwanbin/p/11266025.html