7.28メタクラス上の状態を反映して

ポリモーフィズム

1.多型は何ですか

多型は、物事のクラスを指し、様々な形態を持っています

例えば:

動物の様々な形態があります。

ヒト、イヌ、ブタ

同じように異なるオブジェクトに応答することができ、そして自分自身の異なる実装を持つことができるプログラム手段における多型

2.なぜ我々は多状態が必要なのか

ケーススタディ:

import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass

class People(Animal): #动物的形态之一:人
    def talk(self):
        print('say hello')

class Dog(Animal): #动物的形态之二:狗
    def talk(self):
        print('say wangwang')

class Pig(Animal): #动物的形态之三:猪
    def talk(self):
        print('say aoao')
        
peo=People()
dog=Dog()
pig=Pig()

#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()

#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
    obj.talk()
func(peo)
func(dog)
func(pig)

Pythonのデフォルトは、多型をサポートすることで、あなたは視覚的に上記のテキスト列によって多状態の利点を理解することができ、それは新しい知識ではありません

だから、どのような多型のメリットとは?

1.プログラムの柔軟性を高めます

  現状を維持することに関係なく、刻々と変化する対象ユーザのようなFUNC(動物)として、呼び出す形の同じ種類であります

2.スケーラビリティプログラムの量を増やします

  新しい動物のカテゴリを継承したクラスを作成し、ユーザーが自分のコードを変更、または呼び出すことFUNC(動物)を使用する必要はありません  

class Cat(Animal): #动物的另外一种形态:猫
    def talk(self):
        print('say miao')
def func(animal): #对于使用者来说,自己的代码根本无需改动
    animal.talk()
cat1=Cat() #实例出一只猫
func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能
say miao
'''
这样我们新增了一个形态Cat,由Cat类产生的实例cat1,使用者可以在完全不需要修改自己代码的情况下。使用和人、狗、猪一样的方式调用cat1的talk方法,即func(cat1)
'''

継承の章では、継承は、動物のすべてのサポートされていない多型を提供し、指摘しcat dog pig、彼らが最初に継承しなければならないAnimalために、彼らはあなたが呼び出すときに例外が発生しません、方法をお話し対応できることを確認するために、なるように、クラスを。

もちろん、何の継承が存在しない場合でも、達成するために、サブクラスで動物のコンテンツの規定に完全に基づいて、サブクラスのデザイナーならば、ユーザーは、デザインに実装する設計者を必要とする、このサブクラスのオブジェクトと同じように、他のオブジェクトのように使用することができるようになりますより慎重なときに、クラス!

3.アヒルタイプ

  「それは、のように見えるように聞こえるとアヒルのように歩き場合、それはアヒルである」Pythonの提唱鴨の種類、すなわち、

Pythonプログラマは、通常は、この規格に基づいてプログラムを書きます。既存のオブジェクトのカスタムバージョンを作成したい場合たとえば、オブジェクトが継承することができます

あなたはまた、外観を作成し、のように振る舞うが、それは一般的に疎結合コンポーネントのプログラムを保存するために使用される新しいオブジェクトとの関係がないことができます。

例1:ファイルのようなこれらの作品のオブジェクトが、オブジェクト「のようなファイルと」ライブラリで定義されている基準のさまざまな方法を使って、彼らは組み込みのファイルオブジェクトのメソッドを継承しませんでした

#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass

例2:実際には、我々はそのようなPythonのシーケンス型として、多型の利点をもたらし享受してきた様々な形態を持っている:文字列、リスト、タプル、多型は、以下を反映

#str,list,tuple都是序列类型
s=str('hello')
l=list([1,2,3])
t=tuple((4,5,6))

#我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)

反射

1反射とは何ですか

概念が最初に提案1982年スミスによって反射され、主にプログラムを指し、自身の状態や動作(イントロスペクション)を検出し、修正する機能にアクセスすることができます。それはすぐに反射コンピュータ科学の応用に関する研究につながった概念を前方に置きます。これは、最初のプログラミング言語設計の分野で使用された、とLispとオブジェクト指向の面で実績をあげています。

ものがたり2.python

全反射オブジェクト指向のプログラミング言語は機能を持っています

パイソンは、反射以下の4つの機能によって達成することが

hasattr(object,name) # 判断对象是否拥有某个属性
setattr(object,name,value) #为对象增加新的属性
getattr(object,name,default) #从对象中获取某个属性
delattr(object,name) #从对象中删除某个属性

パラメータオブジェクトは、クラスを含め、任意のオブジェクトにすることができます

3.なぜ我々は反射が必要なのか

クラス定義では、それは設計の属性の一部は完璧ではありませんが、変更を加えたり、新しいプロパティを追加するには後者が必要な場合があり、反射方式を使用すると、ソースコードを変更する必要はありません

もう一つの利点反射:プラグ可能な設計(キー)

ていないにも限り、あなたは私を与えるように私は、その所有してオブジェクトのプロパティをチェックし、これらのオブジェクトの理解を進めるために必要とすることなく、これらのプロパティを使用することができます、既存のプロパティで見つけることができリバース(反射)することにより、既存のプロパティを変更することが制限されています大幅にプログラムの拡張性を向上

使用方法4

ケース1:

class FtpClient:
    'ftp客户端,但是还么有实现具体的功能'
    def __init__(self,addr):
        print('正在连接服务器[%s]' %addr)
        self.addr=addr
f1=FtpClient('192.168.1.1')
# 反射f1中的方法 如果存在就调用
if hasattr(f1,'get'):
    func_get=getattr(f1,'get')
    func_get()
else:
    print('---->不存在此方法')
    print('处理其他的逻辑')

ケース2:

ダイナミックインポートモジュール

1036857-20161222125118901-555913707

元类

1.メタクラスとは何ですか

すべては言葉から来ている:すべてでPythonはオブジェクトです。ケースクラスということも、それの目的ではないのですか?

class Teacher(object):
    school='tsinghua'

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

    def say(self):
        print('%s says welcome to the Beijing' %self.name)
        
t1=Teacher('egon',18)
print(type(t1)) #查看对象t1的类是<class '__main__.Teacher'>

すべてのオブジェクトがインスタンス化されるか、または(クラスインスタンス化プロセスは、クラスコールと呼ばれる)とクラスは、オブジェクトクラス教師コールT1が得られるように、得られたコール

すべてが対象で、そのクラスがターゲットであることをバインドされて、確認してください

tcls = Teacher
li = [Teacher]
def func(cls):
    print(cls)
func(Teacher)
#完全没问题把他当做对象来使用 和其他对象没有任何区别

考え、T1は教師、それをインスタンス化するクラスのオブジェクトである教師をインスタンス化することによって得られますか?

print(type(Teacher))
#<class 'type'>

推測することができる===>教師の生成プロセスが発生している必要があります:教師=タイプ(...)

画像-20181204115918943

**;この時のクラス型のメタクラスと呼ばれるクラスのクラスインスタンスの生成

先生が得られるタイプによってインスタンス化され、その場合には、それがcalssにそれをインスタンス化するために、独自のタイプを呼び出すことができないのですか?

2.プロセス分析のクラスを作成します。

classキーワードは、私たちはクラスの作成を支援する場合には、それが入ってくるパラメータの型がそれをある時に呼んで、私たちはメタクラス教師=タイプ(...)を呼び出す助けるためにバインドされていますか?クラスの重要な要素である必要があり、このクラスは、すなわち、3つの主要コンポーネントがあります

1、クラス名CLASS_NAME = '教師

図2に示すように、基本クラスはclass_basesは(オブジェクト)=です

図3は、クラスの名前空間class_dicクラス名をコードして得られる空間ベースの材料を行うことです

タイプを呼び出すときにターンでは、これら3つのパラメータを渡します

クラスをインスタンス化する独自の

class_name = "Teacher"
class_code = """
def __init__(self,name,age):
    self.name=name
    self.age=age
def say(self):
    print('%s says welcome to the Beijing' %self.name)
"""
class_dict = {}
exec(class_code,None,class_dict)

bases = (object,)

Teacher = type(class_name,bases,class_dict)
print(Teacher)

要約すると、私たちはクラスの作成を支援するためのクラス・キーワードは、以下の4つの手順に分けるべきです

1.クラス名を取得

2.基本クラスを取得します

3.名前空間を取得します。

メタクラスを取得したクラスの4例

要約:クラスのクラスを生成するための、すなわちメタクラス

3.カスタムメタクラスコントロールクラスを作成します。

私は、このようなすべての名前を必要とするなどのメソッドを実装する高度にカスタマイズされたクラスは小文字でなければならないかを考えたい場合、クラス名は、など資本で始めなければなりません

タイプは、必ずしも特定のコードの作成が含ま行われるクラス型を作成し、今、2つの方法でコードを変更する必要があります

1.望ましくないソースコードの種類を変更します

2.新しいメタメタクラスを作成するカスタムクラスを達成するためにクラスを作成するために、独自のクラスを使用しています

クラスは独自のメタクラスのメタクラスは、内蔵のメタクラスタイプを使用することに加えて、彼のデフォルトタイプで宣言されていない、我々はまた、タイプを継承することができます

クラスのメタクラスの使用を指定するメタクラス、およびメタクラスのキーワードパラメータをカスタマイズします

class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    pass
class Teacher(object,metaclass=Mymeta): # Teacher=Mymeta('Teacher',(object),{...})
    school='tsinghua'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s says welcome to the Beijing' %self.name)

需要

1.仕様クラス名は大文字でなければなりません

2.クラスは、ドキュメンテーションコメントを含める必要があります

class MyMate(type):
    def __init__(self,name,bases,dic):
        print("run")
        if not dic.get("__doc__"):
            raise TypeError("类必须有文档注释!")
        if not name.istitle():
            raise TypeError("类名必须大写开头!")
        super().__init__(name,bases,dic)
class Foo(object,metaclass=MyMate):
    pass

プロジェクトアプリケーション

Youkuのシステムは、このような文は、テーブルを作成した情報に基づいて生成される必要があり、クラスは、それを作成したときに、メタクラスを使用して作成プロセスが簡単にクラスを傍受することができます知っているビルドtable文を生成するクラス関連の情報を取得する必要があります

class MyMetaClass(type):
    def __init__(self,name,bases,dic):
        table_name = name
        columns = self.transfer_columns(dic)
        sql = "create table if not exists %s(%s)" % (table_name,columns)
        # 自动建表
        try:
            OBDB().conn.execute(sql)
        except Exception as e:
            pass
        super().__init__(name,bases,dic)
        
        
        
        
        
        
        
        
s = 10  == s = int
a = type("int")
b = a
b()
c.__class__

4.カスタム呼制御クラスのメタクラス

__call__機能を実行する機会を持っています

このメソッドは、自動的に呼び出すオブジェクト内の実行(オブジェクト括弧)をトリガします

class Foo:
    def __call__(self, *args, **kwargs):
        print("run")
f = Foo() #调用Foo得到f对象
f()#调用对象时 触发__call__的执行

通常それは、通常のオブジェクトは無意味で呼び出して__call__何時にそれを使用しますか?

私たちは、クラスも行われていない、オブジェクト、はFoo()であると言うのはFooクラスの__call__機能を?

誰のFooクラスはそれで?デフォルトのメタクラスの種類、テストにmateclassカスタムのメタクラスで指定されました

#测试
class M(type):
    def __call__(self, *args, **kwargs):
        print("run mateclass __call__")
        pass
    pass
class A(metaclass=M):
    pass
print(A())
#输出 run mateclass __call__
#输出 None

カバー__call__上の注意機能

クラスAを呼び出すとき、最初の行は、出力を示し、実際に自動的に実行される__call__機能、

2行目は、なぜ?である、空白を出力し__call__、コメントがアップし、再びテストした印刷結果がターゲットになってお送りします!

あなたは明示的にプロセスのオブジェクトを作成する必要があります:最初のオブジェクトの名前空間に保存されている初期化属性を実行するために、空のオブジェクトを作成します!
だから、オブジェクトの初期化の完了が呼び出し元に返されますが、これは、2つの段階__call__関数の中で行われなければなりません

カバーたら__call__機能、あなたは、上記の手順を完了するために、所有している必要があり

class MyMate(type):
    def __call__(self, *args, **kwargs):
        # 创建空对象
        # 调用init
        # 返回初始化后的对象
        obj = object.__new__(self)
        self.__init__(obj,*args,**kwargs)
        return obj
class Foo(metaclass=MyMate):
    def __init__(self):
        print("初始化对象")
f = Foo()
print(f)

メタクラスによってクラスのプロセス・オブジェクト・インスタンスを制御します

単にカバー__call__の機能を我々はインスタンス化プロセスの制御を完了することができるようになります

#需求:
#2.要求实例化时传参必须为关键字形式,否则抛出异常TypeError: must use keyword argument
#3.key作为用户自定义类产生对象的属性,且所有属性变成大写
class Mymetaclass(type):
    def __call__(self, *args, **kwargs):
        if args:
            raise TypeError('must use keyword argument for key function')
        obj = object.__new__(self) #创建对象,self为类Chinese

        for k,v in kwargs.items():
            obj.__dict__[k.upper()]=v
        return obj
class Chinese(metaclass=Mymetaclass):
    country='China'
    tag='Legend of the Dragon' #龙的传人
    def walk(self):
        print('%s is walking' %self.name)
p=Chinese(name='egon',age=18,sex='male')
print(p.__dict__)
彼は加えました:

プロセスは、クラスの先生がMymetaを呼び出しているだけでなく、オブジェクトMymetaクラスのタイプは、あなたがMymeta理由を呼び出すことができます生成し、それが実現されなければならない__call__方法を、私たちは独自のメソッドを書く場合でも、クラスも、作成することができるタイプのため、すでにデフォルトしている__call__の実装
この方法は、少なくとも3つのことを行う必要があります

#伪代码
 class type:
     def __call__(self, *args, **kwargs): #self=<class '__main__.Mymeta'>
         obj=self.__new__(self,*args,**kwargs) # 产生Mymeta的一个对象
         self.__init__(obj,*args,**kwargs) 
         return obj

単一要素のクラス例

シングルトンとは何ですか

単一の実施形態を意味すると、単一インスタンスで持つことができるオブジェクト・クラスの1つのインスタンスを指し

なぜシングルトンを使用します

クラスデータのシングルトンインスタンスが変更されていない場合、データは変更されません

このような音楽プレーヤプログラムを開発して、音楽プレーヤーは、あなたが歌を切断した場合、既存のプレーヤーを再作成または使用するプレーヤーは、それについて考える、オブジェクトとしてパッケージ化することができますか?

プレイヤーデータとビジネスロジックが新しい作成する必要はありません同じなので、ためには、シングルモードの実施形態を使用することが好ましいリソースを節約します

2つのオブジェクトが同一のデータがある場合には2つのリソースを占有する必要はありません

#使用classmethod 实现单例
class Player():
    def __init__(self):
        print("创建播放器了")
    __play = None
    @classmethod
    def get_player(cls):
        if not cls.__play:
            cls.__play = Player()
        return cls.__play


p1 = Player.get_player();
p1 = Player.get_player();
p1 = Player.get_player();
p1 = Player.get_player();

のない単一の実施形態ように、このメソッドは、クラスをインスタンス化するために直接呼び出すために、ユーザーを防ぐことはできません。

メタクラスは、シングルトンを実装します

#在类定义时 自动执行init 在init中创建实例 call中直接返回已有实例
class MyMeta(type):
    __instance = None

    def __init__(self,name,bases,dic):
        if not self.__instance:
            self.__instance = object.__new__(self)
            self.__init__(self.__instance)

        super().__init__(name, bases, dic)


    def __call__(cls):
        return cls.__instance

class Player(metaclass=MyMeta):
    def __init__(self):
        print("创建播放器了")
Player()
Player()
# 仅执行一次创建播放器

6.プロパティメタクラスを探します

クラスは、両方の親クラスのメタクラスは、プロパティがどのような順序を見つける必要がありました場合は?

MROは、オーダーリストに基づいています何のメタクラスがない場合にリコールした後、ポイントは我々がそれを行うために使用されるクラス、メタクラスプロパティとして元のクラスを増やすことを、今でも同じであるプロパティを見て?さあ例を見て

class Mymeta(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    n=444
    def __new__(cls, *args, **kwargs):
        pass
class Bar(object):
    n = 333
    def __new__(cls, *args, **kwargs):
        pass
class Foo(Bar):
    n=222
    def __new__(cls, *args, **kwargs):
        pass
class Teacher(Foo,metaclass=Mymeta):
    n=111
    def __new__(cls, *args, **kwargs):
        pass
    school='Tsinghua'
print(Teacher.__new__)
print(Teacher.n)

テスト結果があることを示しています。プロパティの順序は、まだリストの順番クラスに存在しないトップクラスのオブジェクトは元を探すとき、ユアンクラスはそのようには見えません、次のMROを探している親クラスである場合、クラス型

画像-20181204102324732

7.混乱__new__機能と__init__機能

class M(type):
    def __init__(self,clsname,bases,namespace):
        print("init")
    def __call__(self, *args, **kwargs):
        pass
    pass
class A(metaclass=M):
    n = 1
    pass
print(A.__name__)
print(A.__bases__)
print(A.__dict__)
"""输出
init
A
(<class 'object'>,)
{'__module__': '__main__', 'n': 1, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
"""

我々はすでに知っていることを__init__作成プロセスがクラスを制御することができますが、今、私たちは、情報の三つの基本的なカテゴリがされているが、コードで何を初期化しない参照してください、これが作成されたクラスがすでに完了していることを示します

class M(type):
    def __new__(cls, *args, **kwargs):
        print("new")
        #return type.__new__(cls,*args,**kwargs)
    def __init__(self,clsname,bases,namespace):
        print("init")
class A(metaclass=M):
    n = 1
print(A.__name__)
print(A.__bases__)
print(A.__dict__)
"""输出
new
Traceback (most recent call last):
  File "/Users/jerry/PycharmProjects/元类属性查找.py", line 43, in <module>
    print(A.__name__)
AttributeError: 'NoneType' object has no attribute '__name__'"""

行っ__new__機能が、実行されなかった__init__ので、__new__関数が実際にクラスを作成する方法である、戻り値とを持っている必要があり、新たなだけ作成されますinit関数のクラスの実装を成功さ、戻り値の型がある__type__実行するとき__init__の機能を、

ウィル__new__注釈付きのコードはすべての通常を開きます!もう一度擬似コードの第四四半期を確認

**概要:元クラス__new__ ** __init__は、クラスオブジェクトを作成するために使用されるクラスの初期化のための追加的な情報であり、

おすすめ

転載: www.cnblogs.com/PowerTips/p/11261388.html