python - 콤마 - 파이썬 특수문자 제거




파이썬에서 자동 속성 할당을 수행하는 가장 좋은 방법은 무엇입니까? 좋은 생각입니까? (6)

비슷한 편리 성을 달성하는 더 좋은 방법이 있습니까?

반드시 필요한지는 잘 모르겠지만 다음과 같이 할 수 있습니다.

class Foo(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)


>>> foo = Foo(a = 1, b = 'bar', c = [1, 2])
>>> foo.a
1
>>> foo.b
'bar'
>>> foo.c
[1, 2]
>>> 

예의 피터 Norvig의 파이썬 : 가끔 대답하는 질문 .

클래스를 정의 할 때마다 다음과 같은 코드를 작성하는 대신

class Foo(object): 
     def __init__(self, a, b, c, d, e, f, g):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f
        self.g = g

자동 속성 할당에이 조리법을 사용할 수 있습니다.

class Foo(object):
     @autoassign
     def __init__(self, a, b, c, d, e, f, g):
        pass

두 가지 질문 :

  1. 이 지름길과 관련된 단점이나 함정이 있습니까?
  2. 비슷한 편리 성을 달성하는 더 좋은 방법이 있습니까?

버그 자동 (주로 스타일 론적이지만 한 가지 더 심각한 문제)에 대한 몇 가지 사항이 있습니다.

  1. autoassign 은 'args'속성을 지정하지 않습니다.

    class Foo(object):
        @autoassign
        def __init__(self,a,b,c=False,*args):
            pass
    a=Foo('IBM','/tmp',True, 100, 101)
    print(a.args)
    # AttributeError: 'Foo' object has no attribute 'args'
    
  2. autoassign 은 데코레이터처럼 작동합니다. 그러나 autoassign(*argnames) 은 데코레이터를 반환하는 함수를 호출합니다. 이 마법을 달성하기 위해 autoassign 은 첫 번째 인수의 유형을 테스트해야합니다. 선택이 주어지면 함수의 인수 유형을 테스트하지 않는 것이 더 좋습니다.

  3. sieve , 람다 (lambdas) 내의 람다 (lambdas), 불량배 (ifilters), 많은 조건을 설정하는 데 상당한 양의 코드가 사용 된 것으로 보인다.

    if kwargs:
        exclude, f = set(kwargs['exclude']), None
        sieve = lambda l:itertools.ifilter(lambda nv: nv[0] not in exclude, l)
    elif len(names) == 1 and inspect.isfunction(names[0]):
        f = names[0]
        sieve = lambda l:l
    else:
        names, f = set(names), None
        sieve = lambda l: itertools.ifilter(lambda nv: nv[0] in names, l)
    

    나는 더 간단한 방법이있을 것이라고 생각한다. (아래 참조).

  4. for _ in itertools.starmap(assigned.setdefault, defaults): pass . 나는 map 또는 starmap 이 부작용이 유일한 기능인 함수를 호출하기위한 것이라고 생각하지 않습니다. 평범한 것으로 더 명확하게 쓰여졌을 수 있습니다.

    for key,value in defaults.iteritems():
        assigned.setdefault(key,value)
    

다음은 자동 할당과 동일한 기능을하는 간단한 구현입니다 (예 : 포함 및 제외 할 수 있음). 위의 사항을 해결할 수 있습니다.

import inspect
import functools

def autoargs(*include, **kwargs):
    def _autoargs(func):
        attrs, varargs, varkw, defaults = inspect.getargspec(func)

        def sieve(attr):
            if kwargs and attr in kwargs['exclude']:
                return False
            if not include or attr in include:
                return True
            else:
                return False

        @functools.wraps(func)
        def wrapper(self, *args, **kwargs):
            # handle default values
            if defaults:
                for attr, val in zip(reversed(attrs), reversed(defaults)):
                    if sieve(attr):
                        setattr(self, attr, val)
            # handle positional arguments
            positional_attrs = attrs[1:]
            for attr, val in zip(positional_attrs, args):
                if sieve(attr):
                    setattr(self, attr, val)
            # handle varargs
            if varargs:
                remaining_args = args[len(positional_attrs):]
                if sieve(varargs):
                    setattr(self, varargs, remaining_args)
            # handle varkw
            if kwargs:
                for attr, val in kwargs.items():
                    if sieve(attr):
                        setattr(self, attr, val)
            return func(self, *args, **kwargs)
        return wrapper
    return _autoargs

그리고 그 동작을 확인하기 위해 사용한 단위 테스트는 다음과 같습니다.

import sys
import unittest
import utils_method as um

class Test(unittest.TestCase):
    def test_autoargs(self):
        class A(object):
            @um.autoargs()
            def __init__(self,foo,path,debug=False):
                pass
        a=A('rhubarb','pie',debug=True)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)

        class B(object):
            @um.autoargs()
            def __init__(self,foo,path,debug=False,*args):
                pass
        a=B('rhubarb','pie',True, 100, 101)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)
        self.assertTrue(a.args==(100,101))        

        class C(object):
            @um.autoargs()
            def __init__(self,foo,path,debug=False,*args,**kw):
                pass
        a=C('rhubarb','pie',True, 100, 101,verbose=True)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)
        self.assertTrue(a.verbose==True)        
        self.assertTrue(a.args==(100,101))        

    def test_autoargs_names(self):
        class C(object):
            @um.autoargs('bar','baz','verbose')
            def __init__(self,foo,bar,baz,verbose=False):
                pass
        a=C('rhubarb','pie',1)
        self.assertTrue(a.bar=='pie')
        self.assertTrue(a.baz==1)
        self.assertTrue(a.verbose==False)
        self.assertRaises(AttributeError,getattr,a,'foo')

    def test_autoargs_exclude(self):
        class C(object):
            @um.autoargs(exclude=('bar','baz','verbose'))
            def __init__(self,foo,bar,baz,verbose=False):
                pass
        a=C('rhubarb','pie',1)
        self.assertTrue(a.foo=='rhubarb')
        self.assertRaises(AttributeError,getattr,a,'bar')

    def test_defaults_none(self):
        class A(object):
            @um.autoargs()
            def __init__(self,foo,path,debug):
                pass
        a=A('rhubarb','pie',debug=True)
        self.assertTrue(a.foo=='rhubarb')
        self.assertTrue(a.path=='pie')
        self.assertTrue(a.debug==True)


if __name__ == '__main__':
    unittest.main(argv = sys.argv + ['--verbose'])

추신. autoassign 또는 autoargs 사용하면 IPython 코드 완성과 호환됩니다.


위와 비슷하지만 같지는 않지만 ... argskwargs 다루는 것은 매우 짧습니다.

def autoassign(lcls):
    for key in lcls.keys():
        if key!="self":
            lcls["self"].__dict__[key]=lcls[key]

다음과 같이 사용하십시오.

class Test(object):
    def __init__(self, a, b, *args, **kwargs):
        autoassign(locals())

하나의 단점 : 많은 IDE가 __init__.py 를 구문 분석하여 객체의 속성을 찾습니다. IDE에서 자동 코드 완성 기능을보다 기능적으로 사용하려면 구식 방식으로 철자를 쓰는 것이 좋습니다.


이 패키지에서 이제

  • answer-3653049 @autoargs 영감을받은 answer-3653049
  • @autoprops 에 의해 생성 된 필드를 @property 로 변환하여 enforce 또는 pycontracts 와 같은 유효성 검사 라이브러리와 함께 사용합니다.

이것은 파이썬 3.5+


Python 3.7 이상 에서는 데이터 클래스를 사용하여 원하는 것을 얻을 수 있습니다.

자동 할당 된 속성 인 클래스의 필드 를 정의 할 수 있습니다.

그것은 다음과 같이 보일 것입니다 :

@dataclass
class Foo:
    a: str
    b: int
    c: str
    ...

__init__ 메쏘드는 클래스에 자동으로 생성 될 것이고, 인스턴스 생성의 인자들을 그 속성들에 할당 할 것이다 (그리고 인자들을 확인한다).

여기에 유형 힌팅이 필요하므로이 예제에서 intstr 을 사용한 이유입니다. 입력란의 유형을 모르는 경우 typing 모듈에서 모두를 사용할 수 있습니다.





decorator