pythonのアクセサリー、魔法のプロパティ、withと「コンテキストマネージャ」

18267 ワード

Pythonのクローズ
def deco(x, y):
    def wrapper(z):
        return x+y+z
    return wrapper

d = deco(100, 200)

print(d(300))  // 600

  :  、    、  、              ?
1.                ,,,               
2.                ,,,               
3.             ,,,               ,       +  
4.              ,,,       +    ,       +  

デコレーション
   property  
                       ,         

class Goods:
    @property
    def size(self):
        return 100

g = Goods()

print(g.size)  # 100
Python property      :property              ,         。
   ,  ,  
       ,       
def current_func(func):
    func()

def f1():
    print('This is a function-1')

def f2():
    print('This is a function-2')

current_func(f1)
current_func(f2)

    :
This is a function-1
This is a function-2

新しいクラス、3種類の@property装飾器を備えています
class Goods:
    """python3     object 
         python2、3          ,     python3   @xxx.setter  @xxx.deleter
    """
    @property
    def size(self):
        return 100

    @size.setter
    def size(self, value):
        print("@size.setter")

    @size.deleter
    def size(self):
        print("@size.deleter")

g = Goods()

print(g.size)         @property     price   ,         
g.size = 200          @price.setter     price   ,   200         
del g.size            @price.deleter     price   

         property       setter,deleter  


                        :
class Goods:
    def __init__(self):
        self.__money = 200

    def get_money(self):
        print("get __money")
        return self.__money

    def set_money(self, value):
        print("set __money")
        self.__money = value

    def del_size(self):
        print("del __money")
        del self.__money

    m = property(get_money, set_money, del_size)

g = Goods()

print(g.m)
g.m = 500
del g.m

    :
get __money
200
set __money
del __money

[関数|クラス]をカスタマイズしたアクセラレータ
関数の装飾器、関数の呼び出し方式を修正しないで、依然として出力を修正することができます
def deco(func):
    print("    ------")
    def wrapper():
        print("  1 2 3")
        func()
    return wrapper

         deco      test   func  deco,      test
@deco  #     test = deco(test)
def test():
    print("test function")

print("      ---")
test()

    :
    ------
      ---
  1 2 3
test function

 Python    @deco  ,          

モディファイヤにパラメータを渡すには
def deco(func):
    def wrapper(name):
        print("  1 2 3")
        func(name)
    return wrapper

@deco  #     test = deco(test)
def test(name):
    print("name = " + name)

test("libai")

    :
  1 2 3
name = libai

*argsで任意のパラメータを入力できます
def decorator(func):
    def wrapper(*args):  //   
        func(*args)
    return wrapper

@decorator
def f0():
    print("no args")

@decorator
def f1(name):
    print("name = " + name)

@decorator
def f2(name, age):
    print("name = " + name + ", age = " + str(age))

f0()
f1("libai")
f2('libai', 22)

    :
no args
name = libai
name = libai, age = 22

アクセラレータが戻り値を受け取る
def deco(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)  //        return
    return wrapper

@deco
def test(name):
    print("name = " + name)
    return "hello"

ret = test("libai")
print(ret)

    :
name = libai
hello

装飾器の最終形態、*kwはキーワードパラメータを表し、余分なキーワードは辞書として印刷されます.
def decorator(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

コード実装を破壊せず、コード多重性を実現し、複数のアクセサリーを積み重ねて使用できる
複数のアクセサリが同じ関数を装飾する
def deco_1(func):
    print("----   -1----")
    def wrapper(*args, **kwargs):
        print("----   -1--    ----")
        return func(*args, **kwargs)
    return wrapper

def deco_2(func):
    print("----   -2----")
    def wrapper(*args, **kwargs):
        print("----   -2--    ----")
        return func(*args, **kwargs)
    return wrapper

@deco_1
@deco_2  //     deco_2,    deco_1
def test(name):
    print("name = " + name)

test("libai")

    :
----   -2----
----   -1----
----   -1--    ----
----   -2--    ----
name = libai

アクセサリー類
class Test():
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print("     __call__  ")
        return self.func(*args, **kwargs)

@Test
def func(name):
    print("name = " + name)

func("libai")

    :
     __call__  
name = libai

デコレーションパラメータ
def set_level(level):
    def deco(func):
        def inner(*args, **kwargs):
            if level == 1:
                print("----    --1--  ----")
            elif level == 2:
                print("----    --3--  ----")
            else:
                print("----    --3--  ----")
            func(*args, **kwargs)
        return inner
    return deco


@set_level(1)
def test(name):
    print("name = " + name)

test("1000")

    :
----    --1--  ----
name = 1000

装飾器、タイプ検出に変更し、不一致が検出された場合はprintと書き込みなし
def deco(**kwargs): #      **kwargs
    def wrapper(obj): #    wrapper   earth
        print('========================')
        for key,value in kwargs.items(): # .items()      
            setattr(obj, key, Type(key, value))
        return obj
    print(kwargs)
    return wrapper

#      
class Type:
    def __init__(self, key, except_type):
        self.key = key
        self.except_type = except_type
    def __get__(self, instance, owner):
        print('get   ')
        print(instance)
        print(owner)
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        print('set   ')
        print(instance)
        print(value)
        if not isinstance(value,self.except_type):
            print("     %s " %self.except_type)
            return
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        print('del   ')
        print(instance)
        del instance.__dict__[self.key]

@deco(name=str,age=int) #name      str,age     int
class earth:
    def __init__(self, name, age):
        self.name = name
        self.age = age

e = earth('libai', '23') #  set  

print('*************************************************')
print(earth.__dict__)
print(e.__dict__)

    :
{'name': , 'age': }
========================
set   
<__main__.earth object="" at="">
libai
set   
<__main__.earth object="" at="">
23
      
*************************************************
{'__module__': '__main__', '__init__': , '__dict__': , '__weakref__': , '__doc__': None, 'name': <__main__.type object="" at="">, 'age': <__main__.type object="" at="">}
{'name': 'libai'}


@propertyとは、装飾されたクラスや関数をパラメータとしてproperty(クラス)に入力し、実行後に装飾されたクラスに戻り値を割り当てます.以下はカスタム@propertyで、オリジナルの@propertyと似た機能があります
class Lazyproperty:
    def __init__(self, func):
        self.func = func
        print('func = ', self.func)
    def __get__(self, instance, owner):
        print('instance = ', instance)
        print('owner = ', owner)
        #      self.func(instance)        print   ,
        #       test   ,                 test   
        print('------------------>>>', self.func(instance))
        print('***************************************************')
        return self.func(instance)

class earth:
    def __init__(self):
        pass
    @Lazyproperty
    def test(self):
        print('test')
        return '   ?'

e = earth()
print(e.test)

    :
func =  
instance =  <__main__.earth object="" at="">
owner =  
test
------------------>>>    ?  # test      
***************************************************
test
   ?

Pythonの魔法属性__doc__はクラスの記述情報を表し、この属性は継承できない
class Foo:
    """      ,          """
    def func(self):
        pass

class Son(Foo): # __doc__       
    pass

f = Foo()
print(Foo.__dict__)
print(Son.__dict__)
print(f.__dict__)

    :
{'__module__': '__main__', '__doc__': '      ,          ', 'func': , '__dict__': , '__weakref__': }
{'__module__': '__main__', '__doc__': None}
{}
__module__および__class__
__module__               
__class__               

test.py   
class Person(object):
    def __init__(self):
        self.name = 'laowang'

main.py  
from test import Person
obj = Person()
print(obj.__module__)  #    test  :  Person     
print(obj.__class__)  #    test.Person  :  Person    
__init__初期化方法
     ,        ,      
class Person:
    def __init__(self, name):
        self.name = name
        self.age = 18

obj = Person('laowang')  #         __init__   

構造関数__del__オブジェクトがメモリから解放されると、自動的に実行がトリガーされ、インスタンスがシステムによって回収されるとトリガーされる
           ,      。
 :         ,  Python       ,                   ,
         Python      ,  ,__del__                       。

class earth:
    def __init__(self):
        self.name = 'libai'
    def __del__(self):
        print('del is work')
e = earth()
print(e.name)
del e.name           __del__   

print("program end")
            ,   __del__   

    :
libai
program end
del is work
__call__オブジェクトの後ろに括弧を付け、実行をトリガーします.
       ,    。
 :__init__              , :   =   () ;    __call__                 , :  ()     ()()

class Foo:
    def __init__(self):
        pass

    def __call__(self, *args, **kwargs):
        print('__call__')


obj = Foo()       __init__
obj()       __call__,    Foo    __call__   
__dict__クラスまたはオブジェクトのすべてのプロパティ
          
          ;             , :

class Province(object):
    country = 'China'

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

    def func(self, *args, **kwargs):
        print('func')

      , :   、  、
print(Province.__dict__)
  :{'__dict__': , '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__': , 'func': , '__init__': }

obj1 = Province('  ', 10000)
print(obj1.__dict__)
     obj1    
  :{'count': 10000, 'name': '  '}

obj2 = Province('  ', 20000)
print(obj2.__dict__)
     obj1    
  :{'count': 20000, 'name': '  '}
__str__このメソッドの戻り値は、オブジェクトの印刷時にデフォルトで出力されます.
         __str__  ,print()         __str__    ,           。
class Foo:
    def __str__(self):
        return 'laowang'

obj = Foo()
print(obj)
  :laowang

printは__str__メソッドを呼び出し、__repr__はインタラクティブインタフェースが返す値である.
カスタム__repr__メソッドから、__repr____strが同時に存在する場合、__str__メソッドが実行され、__str__が存在しない場合、__repr__が実行される
class test:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return '    %s,    %s' %(self.name, self.age)

    def __repr__(self):
        return "return repr"

t = test('libai', 20)
print(t)

    :
    libai,    20

反復メソッド、__iter__および__next__
class Fib():
    def __init__(self):
        self.a = 0
        self.b = 1

    def __iter__(self): #        ,    ,         __iter__   
        print("run __iter__ function")
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a+self.b
        if self.a > 10:
            raise StopIteration('   ') # for    StopIteration  ,     next()
        return self.a,self.b

f = Fib()
print(next(f))
print(next(f))
print('==========================')
for i in f:
    print(i, end=", ")

    :
(1, 1)
(1, 2)
==========================
run __iter__ function
(2, 3), (3, 5), (5, 8), (8, 13),
__getitem____setitem____delitem__
      ,   。        、  、    
class Foo(object):

    def __getitem__(self, key):
        print('__getitem__', key)

    def __setitem__(self, key, value):
        print('__setitem__', key, value)

    def __delitem__(self, key):
        print('__delitem__', key)

obj = Foo()

result = obj['k1']      #        __getitem__
obj['k2'] = 'laowang'   #        __setitem__
del obj['k1']           #        __delitem__
__getslice____setslice____delslice__
           , :  
class Foo(object):

    def __getslice__(self, i, j):
        print('__getslice__', i, j)

    def __setslice__(self, i, j, sequence):
        print('__setslice__', i, j)

    def __delslice__(self, i, j):
        print('__delslice__', i, j)

obj = Foo()

obj[-1:1]                   #        __getslice__
obj[0:1] = [11,22,33,44]    #        __setslice__
del obj[0:2]                #        __delslice__
__getattribute__プロパティで、プログラムのクラッシュを防止
class Earth:
    def __init__(self, name):
        self.name = name

    def __getattr__(self, item):
        print("getattr is work,get the ", item)
    
             __getattribute__   ,   __getattribute__         __getattr__   
    def __getattribute__(self, item): 
        print('getattribute is work, get the ', item)
        raise AttributeError("     ") #       ,      ,raise    __getattr__ 

e = Earth('game')
e.name
e.none

    :
getattribute is work, get the  name  #name   
getattr is work,get the  name
getattribute is work, get the  none  #none    
getattr is work,get the  none

カスタム__format__メソッド、フォーマット出力
format_dict = {
    'ymd' : '{0.year} {0.mon} {0.day}',
    'y-m-d' : '{0.year}-{0.mon}-{0.day}',
    'y:m:d' : '{0.year}:{0.mon}:{0.day}'
}
class Date:
    def __init__(self, year, mon, day):
        self.year = year
        self.mon = mon
        self.day = day
    def __format__(self, format_spec):
        print("my format, format_spec = '%s'" %format_spec)
        if format_spec and format_spec in format_dict:
            return format_dict[format_spec].format(self)
        else:
            return format_dict['ymd'].format(self)
d = Date(2018, 4, 18)
print('{0.year} {0.mon} {0.day}'.format(d)) #        

print(format(d, 'none')) #        
print(format(d, 'y-m-d'))
print(format(d, 'y:m:d'))

    :
my format, format_spec = 'none'
2018 4 18
my format, format_spec = 'y-m-d'
2018-4-18
my format, format_spec = 'y:m:d'
2018:4:18

withと「コンテキストマネージャ」、関数トリガenterとexit
with open("output.txt", "r") as f:
    f.write("Python  ")


       try/finally
f = open("output.txt", "w")
try:
    f.write("python  ")
except IOError:
    print("oops error")
finally:
    f.close()

      、         with    。open             f,    with   
    ,        f.close()   , with        try/finally       。
           ?   with               ,
        (Context Manager)。

コンテキストマネージャ
      __enter__()   __exit__()                 ,        
     with    。  ,  (file)            。

                  ?                ,
      __enter__()   __exit__()   。

class File():

    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode

    def __enter__(self):  #     
        print("entering")
        self.f = open(self.filename, self.mode)
        return self.f

    def __exit__(self, *args):  #      
        print("will exit")
        self.f.close()

__enter__()         ,                ,
__exit__()           。

   File           ,        with    。

with File('out.txt', 'w') as f:
    print("writing")
    f.write('hello, python')
  ,          close    ,        ,
         close        。

1.with File --->   File.__enter__(),      
2.as f -----> f=   
3.with File as f      f=File.__enter__()
4.     

 :        ,             __exit__,        none
 :        ,            __exit__
    a:   __exit__     True,       
    b:   __exit__      True,       
    c: __exit__           with       

  
Python     with                  ,  try/finally      ,
               。

例外情報の場合
>>> abc
Traceback (most recent call last):
  File "", line 1, in 
NameError: name 'abc' is not defined

NameError ----->class
name 'abc' is not defined ----->    
Traceback ----->