6.オブジェクトに向かう:反射、二重下の方法

13500 ワード

一.はんしゃ
反射の概念は1982年にSmithによって初めて提案され、主にプログラムが自身の状態や行為にアクセス、検出、修正できる能力(自省)を指す.この概念の提出はすぐにコンピュータ科学分野の応用反射性に関する研究を引き起こした.まずプログラム言語の設計分野に採用され,Lispとオブジェクト向けの面で成績を収めた.
pythonオブジェクトへの反射:オブジェクト関連のプロパティを文字列で操作します.pythonのすべてのものはオブジェクトです(反射を使用できます)
自省できる4つの関数
次の方法はクラスとオブジェクトに適用されます(すべてがオブジェクトであり、クラス自体もオブジェクトです).
class Foo:
    f = '      '
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

#         
print(hasattr(obj,'name'))
print(hasattr(obj,'say_hi'))

#    
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()

print(getattr(obj,'aaaaaaaa','    ')) #  

#    
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__)
print(obj.show_name(obj))

#    
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#   ,   

print(obj.__dict__)

         

オブジェクトへの反射
class Foo(object):
 
    staticField = "old boy"
 
    def __init__(self):
        self.name = 'wupeiqi'
 
    def func(self):
        return 'func'
 
    @staticmethod
    def bar():
        return 'bar'
 
print getattr(Foo, 'staticField')
print getattr(Foo, 'func')
print getattr(Foo, 'bar')

クラスへの反射
import sys


def s1():
    print 's1'


def s2():
    print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')

現在のモジュールの反射
#        
def test():
    print('from the test')
"""
    :
    module_test.py
    index.py
 
    :
    index.py
"""
#          
import module_test as obj

#obj.test()

print(hasattr(obj,'test'))

getattr(obj,'test')()

       

その他のモジュールの反射
反射の適用:
反射の4つの関数を理解した.では、反射はいったい何の役に立つのでしょうか.その応用シーンは何ですか?
ブラウザを開いて、ウェブサイトにアクセスして、ログインをクリックしてログインインタフェースにジャンプして、登録をクリックして登録インタフェースにジャンプして、など、実はあなたがクリックしたのは実は1つのリンクで、それぞれのリンクには関数や方法があります.
class User:
    def login(self):
        print('        ')
    
    def register(self):
        print('        ')
    
    def save(self):
        print('        ')


while 1:
    choose = input('>>>').strip()
    if choose == 'login':
        obj = User()
        obj.login()
    
    elif choose == 'register':
        obj = User()
        obj.register()
        
    elif choose == 'save':
        obj = User()
        obj.save()
        

反射前の解決法を学ばなかった
class User:
    def login(self):
        print('        ')
    
    def register(self):
        print('        ')
    
    def save(self):
        print('        ')

user = User()
while 1:
    choose = input('>>>').strip()
    if hasattr(user,choose):
        func = getattr(user,choose)
        func()
    else:
        print('    。。。。')

反射を学んだ後の解決策
どれほど簡単か、一目瞭然です.
二.関数vsメソッド
ここまで勉強して、私はやっとあなたが今まで持っていた疑問に答えることができます.それは、以前の学習でlen()を関数(口誤時に方法と呼ぶ)と呼んでいたのにstrのstripのように方法と呼ばれていたのですが、それはいったい何と呼ばれていますか.関数と方法の違いと共通点は何ですか?ここで正式に説明します.
2.1印刷関数(メソッド)名による決定
def func():
    pass

print(func)  # 


class A:
    def func(self):
        pass
    
print(A.func)  # 
obj = A()
print(obj.func)  # >

View Code
2.2 typesモジュールによる検証
from types import FunctionType
from types import MethodType

def func():
    pass


class A:
    def func(self):
        pass

obj = A()


print(isinstance(func,FunctionType))  # True
print(isinstance(A.func,FunctionType))  # True
print(isinstance(obj.func,FunctionType))  # False
print(isinstance(obj.func,MethodType))  # True

View Code
2.3静的方法は関数である
from types import FunctionType
from types import MethodType

class A:
    
    def func(self):
        pass
    
    @classmethod
    def func1(self):
        pass
    
    @staticmethod
    def func2(self):
        pass
obj = A()

#          
# print(isinstance(A.func2,FunctionType))  # True
# print(isinstance(obj.func2,FunctionType))  # True

View Code
2.4関数と方法の違い
では,関数と方法は上記の違いに加えて,いくつかの違いをまとめた.
(1)関数は明示的にデータを伝達する.len()関数として処理するデータを渡すことを指定します.
(2)関数は対象とは無関係である.
(3)メソッドにおけるデータは暗黙的に伝達される.
(4)メソッドはクラス内部のデータを操作できる.
(5)メソッドはオブジェクトに関連付けられている.strip()メソッドを使用すると、strオブジェクトによって呼び出されるのではないでしょうか.たとえば、文字列sがあり、s.strip()のように呼び出されます.はい、strip()メソッドはstrオブジェクトに属します.
私たちは日常的に呼称関数や方法を口語化するのは厳密ではないかもしれませんが、私たちの心の中では両者の違いを知っていなければなりません.
他の言語では、Javaではメソッドのみ、Cでは関数のみ、C++かどうかは、クラスにあるかどうかによって異なります.
三.ダブルダウンメソッド
定義:二重下法は特殊な方法で、彼は解釈器が提供した爽下線加法名加二重下線_メソッド名_の特殊な意義を持つ方法で、二重の方法は主にpythonソースコードのプログラマーが使用して、私達は開発の中でできるだけ二重の方法を使用しないで、しかし二重の方法を深く研究して、更に私達がソースコードを読むのに役立ちます.
呼び出し:異なる二重ダウンメソッドには異なるトリガ方式があり、墓を盗んだときにトリガした機関のように、いつの間にか二重ダウンメソッドがトリガされます.例えば:init
3.01 __len
class B:
    def __len__(self):
        print(666)

b = B()
len(b) # len          __len__  。

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __len__(self):
        return len(self.__dict__)
a = A()
print(len(a))

View Code
3.02 __hash
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __hash__(self):
        return hash(str(self.a)+str(self.b))
a = A()
print(hash(a))

View Code
3.03 str
クラスに__が定義されている場合str__メソッドを使用すると、オブジェクトを印刷するときにメソッドの戻り値がデフォルトで出力されます.
class A:
    def __init__(self):
        pass
    def __str__(self):
        return '  '
a = A()
print(a)
print('%s' % a)

View Code
3.04 repr
クラスに__が定義されている場合repr__メソッドを使用すると、repr(オブジェクト)の場合、デフォルトでメソッドの戻り値が出力されます.
class A:
    def __init__(self):
        pass
    def __repr__(self):
        return '  '
a = A()
print(repr(a))
print('%r'%a)

View Code
3.05 call
オブジェクトの後ろにかっこを付け、実行をトリガーします.
注意:構築方法_new__の実行は、オブジェクトの作成によってトリガーされます.すなわち、オブジェクト=クラス名()です.一方、callメソッドの実行は、オブジェクト()またはクラス()()()であるオブジェクトの後かっこでトリガーされます.
class Foo:

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

        print('__call__')


obj = Foo() #    __init__
obj()       #    __call__

View Code
3.06 __eq
class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        if  self.a == obj.a and self.b == obj.b:
            return True
a = A()
b = A()
print(a == b)

View Code
3.07 del
オブジェクトがメモリから解放されると、自動的に実行がトリガーされます.
注意:この方法は一般的に定義する必要はありません.Pythonは高度な言語であり、プログラマは使用時にメモリの割り当てと解放に関心を持つ必要はありません.この作業はPython解釈器に任せて実行されるため、構造関数の呼び出しは解釈器がゴミ回収を行うときに自動的にトリガーされます.
3.08__new
class A:
    def __init__(self):
        self.x = 1
        print('in init function')
    def __new__(cls, *args, **kwargs):
        print('in new function')
        return object.__new__(A, *args, **kwargs)

a = A()
print(a.x)

View Code
class A:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            obj = object.__new__(cls)
            cls.__instance = obj
        return cls.__instance

単一モード
単例モードの具体的な分析
単例モードは一般的なソフトウェア設計モードである.そのコア構造には、単一のクラスと呼ばれる特殊なクラスが1つしか含まれていません.単一のインスタンスモードにより、システム内の1つのクラスに1つのインスタンスしかなく、外部からのアクセスが容易であることを保証し、インスタンスの個数の制御を容易にし、システムリソースを節約することができる.システム内のクラスのオブジェクトが1つしか存在しない場合は、単一のモードが最善の解決策です.【シングル・モード・モチベーションの採用、理由】システム内のいくつかのクラスにとって、1つのインスタンスのみが重要である.例えば、1つのシステムに複数の印刷タスクが存在してもよいが、1つの作業中のタスクしか存在しない.1つのシステムにはウィンドウマネージャまたはファイルシステムが1つしかありません.システムには、タイマツールまたはID(シーケンス番号)ジェネレータが1つしかありません.Windowsでは、タスクマネージャを1つだけ開くことができます.メカニズムを使用してウィンドウオブジェクトを一意化しないと、複数のウィンドウがポップアップされ、これらのウィンドウの表示内容が完全に一致している場合は、重複オブジェクトであり、メモリリソースを浪費します.これらのウィンドウに表示される内容が一致しないと、ある瞬間にシステムに複数の状態があり、実際と一致しないことを意味し、ユーザーに誤解をもたらし、どちらが真実なのか分からない.したがって、システム内のオブジェクトの一意性、すなわちクラスに1つのインスタンスしか存在しないことを確認することが重要になる場合があります.クラスに1つのインスタンスしかなく、このインスタンスがアクセスしやすいことを保証するにはどうすればいいですか?グローバル変数を定義すると、オブジェクトがいつでもアクセスできるようになりますが、複数のオブジェクトをインスタンス化することはできません.より良い解決策は、クラス自身がその唯一のインスタンスを保存する責任を負うことです.このクラスは、他のインスタンスが作成されないことを保証し、インスタンスにアクセスする方法を提供します.これが単例モードのモード動機である.【単一モードの長所と短所】【利点】一、インスタンス制御単一モードは、他のオブジェクトが独自の単一オブジェクトのコピーをインスタンス化することを阻止し、すべてのオブジェクトが一意のインスタンスにアクセスすることを保証する.二、柔軟性クラスはインスタンス化プロセスを制御するため、クラスはインスタンス化プロセスを柔軟に変更することができる.【欠点】1、オーバーヘッドの数は少ないが、オブジェクトが参照を要求するたびにクラスのインスタンスが存在するかどうかを確認する場合は、オーバーヘッドが依然として必要である.この問題は、静的初期化を使用して解決できます.二、単一のオブジェクト(特にクラスライブラリで定義されているオブジェクト)を使用する場合、開発者はnewキーワードを使用してオブジェクトをインスタンス化できないことを覚えておく必要があります.ライブラリのソースコードにアクセスできない可能性があるため、アプリケーション開発者は、このようなインスタンス化ができないことに気づく可能性があります.三、オブジェクトの生存期間は単一のオブジェクトを削除する問題を解決できない.メモリ管理を提供する言語(.NET Frameworkベースの言語など)では、インスタンスへのプライベート参照が含まれているため、インスタンスの割り当てを取り消すことができるのは、単一のクラスのみです.C++などの言語では、他のクラスはオブジェクトインスタンスを削除できますが、単一のクラスで懸濁参照が発生します.
3.09 __item__シリーズ
class Foo:
    def __init__(self,name):
        self.name=name

    def __getitem__(self, item):
        print(self.__dict__[item])

    def __setitem__(self, key, value):
        self.__dict__[key]=value
    def __delitem__(self, key):
        print('del obj[key] ,   ')
        self.__dict__.pop(key)
    def __delattr__(self, item):
        print('del obj.key ,   ')
        self.__dict__.pop(item)

f1=Foo('sb')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='alex'
print(f1.__dict__)

View Code
3.10コンテキストマネージャ関連
enter __exit
#              with  as       。
class A:
    def __init__(self, text):
        self.text = text

with A('  ') as f1:
    print(f1.text)

彼らなしではできない
class A:
    
    def __init__(self, text):
        self.text = text
    
    def __enter__(self):  #                 
        self.text = self.text + '   '
        return self  #          f1
    
    def __exit__(self, exc_type, exc_val, exc_tb):  #            f1      
        self.text = self.text + '    '
        
with A('  ') as f1:
    print(f1.text)
print(f1.text)

彼らはこのように操作することができます
class Diycontextor:
    def __init__(self,name,mode):
        self.name = name
        self.mode = mode
 
    def __enter__(self):
        print "Hi enter here!!"
        self.filehander = open(self.name,self.mode)
        return self.filehander
 
    def __exit__(self,*para):
        print "Hi exit here"
        self.filehander.close()
 
 
with Diycontextor('py_ana.py','r') as f:
    for i in f:
        print i

カスタムファイルマネージャ
関連面接問題:
class StarkConfig:
    def __init__(self,num):
        self.num = num
    
    def run(self):
        self()
    
    def __call__(self, *args, **kwargs):
        print(self.num)

class RoleConfig(StarkConfig):
    def __call__(self, *args, **kwargs):
        print(345)
    def __getitem__(self, item):
        return self.num[item]

v1 = RoleConfig('alex')
v2 = StarkConfig('    ')
# print(v1[1])
# print(v2[2])
v1.run()

-------
class UserInfo:
    pass


class Department:
    pass


class StarkConfig:
    def __init__(self, num):
        self.num = num
    
    def changelist(self, request):
        print(self.num, request)
    
    def run(self):
        self.changelist(999)


class RoleConfig(StarkConfig):
    def changelist(self, request):
        print(666, self.num)


class AdminSite:
    
    def __init__(self):
        self._registry = {}
    
    def register(self, k, v):
        self._registry[k] = v


site = AdminSite()
site.register(UserInfo, StarkConfig)
# 1 
# obj = site._registry[UserInfo]()

# 2
obj = site._registry[UserInfo](100)
obj.run()

-------
class UserInfo:
    pass

class Department:
    pass

class StarkConfig:
    def __init__(self,num):
        self.num = num

    def changelist(self,request):
        print(self.num,request)

    def run(self):
        self.changelist(999)

class RoleConfig(StarkConfig):
    def changelist(self,request):
        print(666,self.num)


class AdminSite:

    def __init__(self):
        self._registry = {}

    def register(self,k,v):
        self._registry[k] = v(k)

site = AdminSite()
site.register(UserInfo,StarkConfig)
site.register(Department,RoleConfig)

for k,row in site._registry.items():
    row.run()

-------
class A:
    list_display = []
    
    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display

s1 = A()
print(s1.get_list())

-------
class A:
    list_display = [1, 2, 3]
    def __init__(self):
        self.list_display = []
    def get_list(self):
        self.list_display.insert(0, 33)
        return self.list_display


s1 = A()
print(s1.get_list())

------
class A:
    list_display = []

    def get_list(self):
        self.list_display.insert(0,33)
        return self.list_display

class B(A):
    list_display = [11,22]


s1 = A()
s2 = B()
print(s1.get_list())
print(s2.get_list())

View Code