Program Tip

파이썬 변수가 함수인지 어떻게 감지합니까?

programtip 2020. 10. 2. 23:09
반응형

파이썬 변수가 함수인지 어떻게 감지합니까?


나는 변수가 있고 x그것이 함수를 가리키는 지 아닌지 알고 싶습니다.

다음과 같이 할 수 있기를 바랐습니다.

>>> isinstance(x, function)

그러나 그것은 나에게 준다.

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'function' is not defined

내가 고른 이유는

>>> type(x)
<type 'function'>

Python 2.x 또는 Python 3.2+ 용인 경우 callable(). 이전에는 더 이상 사용되지 않았지만 이제는 더 이상 사용되지 않으므로 다시 사용할 수 있습니다. 여기에서 토론을 읽을 수 있습니다 : http://bugs.python.org/issue10518 . 다음과 같이 할 수 있습니다.

callable(obj)

이것이 Python 3.x이지만 3.2 이전 인 경우 객체에 __call__속성 이 있는지 확인하십시오 . 다음과 같이 할 수 있습니다.

hasattr(obj, '__call__')

자주 제안되는 types.FunctionTypes접근 방식은 내장 기능과 같이 통과하기를 원하는 많은 경우를 다루지 못하기 때문에 올바르지 않습니다.

>>> isinstance(open, types.FunctionType)
False

>>> callable(open)
True

오리 유형 개체의 속성을 확인하는 적절한 방법은 오리 크기의 컨테이너에 맞는지 확인하는 것이 아니라 돌팔이인지 묻는 것입니다. types.FunctionType함수가 무엇인지에 대해 매우 구체적인 아이디어가 없으면 사용 하지 마십시오 .


내장 네임 스페이스에 생성자가없는 내장 유형 (예 : 함수, 생성기, 메서드)은 types모듈에 있습니다. types.FunctionTypeisinstance 호출에서 사용할 수 있습니다 .

In [1]: import types
In [2]: types.FunctionType
Out[2]: <type 'function'>
In [3]: def f(): pass
   ...:
In [4]: isinstance(f, types.FunctionType)
Out[4]: True
In [5]: isinstance(lambda x : None, types.FunctionType)
Out[5]: True

Python 2.1부터 모듈 isfunction에서 가져올 수 있습니다 inspect.

>>> from inspect import isfunction
>>> def f(): pass
>>> isfunction(f)
True
>>> isfunction(lambda x: x)
True

받아 들여진 대답은 그것이 옳다고 생각되는 제안 당시였습니다. 결과적 으로 Python 3.2로 돌아온을 대체 할 수 없습니다callable() . 특히 테스트중인 객체 callable()tp_call필드를 확인합니다 . 평범한 파이썬은 없습니다. 대부분의 제안 테스트는 대부분 정확합니다.

>>> class Spam(object):
...     def __call__(self):
...         return 'OK'
>>> can_o_spam = Spam()


>>> can_o_spam()
'OK'
>>> callable(can_o_spam)
True
>>> hasattr(can_o_spam, '__call__')
True
>>> import collections
>>> isinstance(can_o_spam, collections.Callable)
True

__call__클래스 에서을 제거하여 몽키 렌치를 던져 넣을 수 있습니다 . 그리고 더 흥미 진진하게 유지 __call__하기 위해 인스턴스에 가짜 추가하십시오 !

>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'

이것은 실제로 호출 할 수 없습니다.

>>> can_o_spam()
Traceback (most recent call last):
  ...
TypeError: 'Spam' object is not callable

callable() 올바른 결과를 반환합니다.

>>> callable(can_o_spam)
False

그러나 hasattr입니다 잘못된 :

>>> hasattr(can_o_spam, '__call__')
True

can_o_spam결국 그 속성이 있습니다. 인스턴스를 호출 할 때 사용되지 않습니다.

더 미묘한 것도이 isinstance()문제를 해결합니다.

>>> isinstance(can_o_spam, collections.Callable)
True

이 검사를 이전에 사용하고 나중에 메서드를 삭제했기 때문에 abc.ABCMeta결과를 캐시합니다. 틀림없이 이것은 abc.ABCMeta. 즉, 슬롯 방법은 다른 방법으로 액세스 할 수 없기 때문에 자체 를 사용하는 것보다 결과보다 더 정확한 결과를 생성 수있는 방법은 없습니다.callable()typeobject->tp_call

그냥 사용 callable()


다음은 부울을 반환해야합니다.

callable(x)

Python의 2to3 도구 ( http://docs.python.org/dev/library/2to3.html )는 다음을 제안합니다.

import collections
isinstance(obj, collections.Callable)

http://bugs.python.org/issue7006hasattr(x, '__call__') 때문에 메서드 대신 선택된 것 같습니다 .


callable(x) 전달 된 객체가 Python에서 호출 될 수 있지만 함수가 Python 3.0에 존재하지 않는 경우 true 반환하고 올바르게 말하면 다음을 구분하지 않습니다.

class A(object):
    def __call__(self):
        return 'Foo'

def B():
    return 'Bar'

a = A()
b = B

print type(a), callable(a)
print type(b), callable(b)

<class 'A'> True그리고 <type function> True출력으로 얻을 수 있습니다.

isinstance무언가가 함수인지 판단하기에 완벽하게 잘 작동합니다 (try isinstance(b, types.FunctionType)). 무언가를 호출 할 수 있는지 알고 싶다면 사용 hasattr(b, '__call__')하거나 시도해 볼 수 있습니다.

test_as_func = True
try:
    b()
except TypeError:
    test_as_func = False
except:
    pass

물론 이것은 호출 가능 여부를 알려주지 않지만 TypeError실행될 때 a를 던지 거나 처음에는 호출 할 수 없습니다. 그것은 당신에게 중요하지 않을 수 있습니다.


함수, 메서드, 내장 fun / meth, 람다 등 구문 적으로 함수처럼 보이는 모든 것을 감지하고 싶지만 호출 가능한 객체 ( 메서드가 정의 된 객체)를 제외하려면__call__ 다음을 시도하십시오.

import types
isinstance(x, (types.FunctionType, types.BuiltinFunctionType, types.MethodType, types.BuiltinMethodType, types.UnboundMethodType))

나는 이것을 모듈 is*()검사 코드와 비교 했으며 inspect위의 표현식은 특히 목표가 함수를 필터링하거나 객체의 일반 속성을 감지하는 경우 훨씬 더 완전합니다.


몇 가지 다른 방법이 있습니다.

def isFunction1(f) :
    return type(f) == type(lambda x: x);

def isFunction2(f) :
    return 'function' in str(type(f));

두 번째를 생각 해낸 방법은 다음과 같습니다.

>>> type(lambda x: x);
<type 'function'>
>>> str(type(lambda x: x));
"<type 'function'>"
# Look Maa, function! ... I ACTUALLY told my mom about this!

을 사용해보십시오 callable(x).


함수는 __call__메서드가 있는 클래스 일 뿐이 므로 할 수 있습니다.

hasattr(obj, '__call__')

예를 들면 :

>>> hasattr(x, '__call__')
True

>>> x = 2
>>> hasattr(x, '__call__')
False

이것이 "가장 좋은"방법이지만 호출 가능 여부를 알아야하는 이유에 따라 try / execpt 블록에 넣을 수 있습니다.

try:
    x()
except TypeError:
    print "was not callable"

try / except가 if hasattr(x, '__call__'): x().. hasattr실수로 잘못된 TypeError를 잡을 수 없기 때문에 더 정확 하다고 말할 수 있습니다. 예를 들어 :

>>> def x():
...     raise TypeError
... 
>>> hasattr(x, '__call__')
True # Correct
>>> try:
...     x()
... except TypeError:
...     print "x was not callable"
... 
x was not callable # Wrong!

당신이 배운 경우 C++, 당신은 잘 알고 있어야합니다 function object또는 functor, 그 수있는 모든 개체를 의미합니다 be called as if it is a function.

C ++에서는 an ordinary function함수 객체이고 함수 포인터도 마찬가지입니다. 보다 일반적으로을 정의하는 클래스의 객체도 마찬가지입니다 operator(). C ++ 11과 큰에서 the lambda expression는 IS functor너무합니다.

유사성, Python에서는 functors모두 callable. An ordinary function호출 가능, a lambda expression호출 가능, a functional.partial호출 가능,의 인스턴스 class with a __call__() method호출 가능.


좋습니다. 질문으로 돌아갑니다. I have a variable, x, and I want to know whether it is pointing to a function or not.

날씨를 판단하고 싶다면 객체가 함수처럼 작동한다면에서 callable제안한 방법 @John Feminella은 괜찮습니다.

원하는 경우 judge whether a object is just an ordinary function or not(호출 가능한 클래스 인스턴스 또는 람다식이 아님) xtypes.XXX제안하는 @Ryan것이 더 나은 선택입니다.

그런 다음 해당 코드를 사용하여 실험을 수행합니다.

#!/usr/bin/python3
# 2017.12.10 14:25:01 CST
# 2017.12.10 15:54:19 CST

import functools
import types
import pprint

클래스와 일반 함수를 정의하십시오.

class A():
    def __call__(self, a,b):
        print(a,b)
    def func1(self, a, b):
        print("[classfunction]:", a, b)
    @classmethod
    def func2(cls, a,b):
        print("[classmethod]:", a, b)
    @staticmethod
    def func3(a,b):
        print("[staticmethod]:", a, b)

def func(a,b):
    print("[function]", a,b)

펑터 정의 :

#(1.1) built-in function
builtins_func = open
#(1.2) ordinary function
ordinary_func = func
#(1.3) lambda expression
lambda_func  = lambda a : func(a,4)
#(1.4) functools.partial
partial_func = functools.partial(func, b=4)

#(2.1) callable class instance
class_callable_instance = A()
#(2.2) ordinary class function
class_ordinary_func = A.func1
#(2.3) bound class method
class_bound_method = A.func2
#(2.4) static class method
class_static_func = A.func3

펑터 목록과 유형 목록을 정의합니다.

## list of functors
xfuncs = [builtins_func, ordinary_func, lambda_func, partial_func, class_callable_instance, class_ordinary_func, class_bound_method, class_static_func]
## list of type
xtypes = [types.BuiltinFunctionType, types.FunctionType, types.MethodType, types.LambdaType, functools.partial]

functor가 호출 가능한지 판단하십시오. 보시다시피, 그들은 모두 호출 가능합니다.

res = [callable(xfunc)  for xfunc in xfuncs]
print("functors callable:")
print(res)

"""
functors callable:
[True, True, True, True, True, True, True, True]
"""

펑터의 유형 (types.XXX)을 판단합니다. 그렇다면 펑터의 유형은 모두 동일하지 않습니다.

res = [[isinstance(xfunc, xtype) for xtype in xtypes] for xfunc in xfuncs]

## output the result
print("functors' types")
for (row, xfunc) in zip(res, xfuncs):
    print(row, xfunc)

"""
functors' types
[True, False, False, False, False] <built-in function open>
[False, True, False, True, False] <function func at 0x7f1b5203e048>
[False, True, False, True, False] <function <lambda> at 0x7f1b5081fd08>
[False, False, False, False, True] functools.partial(<function func at 0x7f1b5203e048>, b=4)
[False, False, False, False, False] <__main__.A object at 0x7f1b50870cc0>
[False, True, False, True, False] <function A.func1 at 0x7f1b5081fb70>
[False, False, True, False, False] <bound method A.func2 of <class '__main__.A'>>
[False, True, False, True, False] <function A.func3 at 0x7f1b5081fc80>
"""

데이터를 사용하여 콜 러블 펑터 유형 표를 그립니다.

여기에 이미지 설명 입력

그런 다음 적합한 펑터 유형을 선택할 수 있습니다.

예 :

def func(a,b):
    print("[function]", a,b)

>>> callable(func)
True
>>> isinstance(func,  types.FunctionType)
True
>>> isinstance(func, (types.BuiltinFunctionType, types.FunctionType, functools.partial))
True
>>> 
>>> isinstance(func, (types.MethodType, functools.partial))
False

받아 들여진 대답으로 John Feminella는 다음과 같이 말했습니다.

오리 유형 개체의 속성을 확인하는 적절한 방법은 오리 크기의 컨테이너에 맞는지 확인하는 것이 아니라 돌팔이인지 묻는 것입니다. "직접 비교"접근 방식은 내장과 같은 많은 함수에 대해 잘못된 답을 제공합니다.

함수를 엄격하게 구분하는 두 개의 라이브러리가 있지만 필자는 완전한 비교 테이블을 그립니다.

8.9. types — 동적 유형 생성 및 내장 유형의 이름 — Python 3.7.0 문서

30.13. inspect — 라이브 객체 검사 — Python 3.7.0 문서

#import inspect             #import types
['isabstract',
 'isasyncgen',              'AsyncGeneratorType',
 'isasyncgenfunction', 
 'isawaitable',
 'isbuiltin',               'BuiltinFunctionType',
                            'BuiltinMethodType',
 'isclass',
 'iscode',                  'CodeType',
 'iscoroutine',             'CoroutineType',
 'iscoroutinefunction',
 'isdatadescriptor',
 'isframe',                 'FrameType',
 'isfunction',              'FunctionType',
                            'LambdaType',
                            'MethodType',
 'isgenerator',             'GeneratorType',
 'isgeneratorfunction',
 'ismethod',
 'ismethoddescriptor',
 'ismodule',                'ModuleType',        
 'isroutine',            
 'istraceback',             'TracebackType'
                            'MappingProxyType',
]

"덕 타이핑"은 일반적인 용도로 선호되는 솔루션입니다.

def detect_function(obj):
    return hasattr(obj,"__call__")

In [26]: detect_function(detect_function)
Out[26]: True
In [27]: callable(detect_function)
Out[27]: True

내장 기능에 관해서

In [43]: callable(hasattr)
Out[43]: True

내장 함수인지 사용자 정의 기능인지 확인하기 위해 한 단계 더 가면

#check inspect.isfunction and type.FunctionType
In [46]: inspect.isfunction(detect_function)
Out[46]: True
In [47]: inspect.isfunction(hasattr)
Out[47]: False
In [48]: isinstance(detect_function, types.FunctionType)
Out[48]: True
In [49]: isinstance(getattr, types.FunctionType)
Out[49]: False
#so they both just applied to judge the user-definded

확인 builtin function

In [50]: isinstance(getattr, types.BuiltinFunctionType)
Out[50]: True
In [51]: isinstance(detect_function, types.BuiltinFunctionType)
Out[51]: False

요약

고용 callable기능을 확인 오리 유형,
사용 types.BuiltinFunctionType이 더 지정한 경우 수요.


클래스에도 __call__메서드 가 있으므로 다른 솔루션을 권장합니다.

class A(object):
    def __init__(self):
        pass
    def __call__(self):
        print 'I am a Class'

MyClass = A()

def foo():
    pass

print hasattr(foo.__class__, 'func_name') # Returns True
print hasattr(A.__class__, 'func_name')   # Returns False as expected

print hasattr(foo, '__call__') # Returns True
print hasattr(A, '__call__')   # (!) Returns True while it is not a function

Python 클래스도 호출 가능합니다.

함수를 얻으려면 (그리고 함수로 표준 함수와 람다를 의미합니다) 다음을 사용하십시오.

import types

def is_func(obj):
    return isinstance(obj, (types.FunctionType, types.LambdaType))


def f(x):
    return x


assert is_func(f)
assert is_func(lambda x: x)

대신 검사의 '__call__'(기능에 배타적이지 인), 당신은 사용자 정의 함수는 속성이 있는지 여부를 확인할 수 있습니다 func_name, func_doc등이이 방법에 대한 작업을하지 않습니다.

>>> def x(): pass
... 
>>> hasattr(x, 'func_name')
True

확인하는 또 다른 방법은 모듈 isfunction()방법을 사용하는 것입니다 inspect.

>>> import inspect
>>> inspect.isfunction(x)
True

객체가 메소드인지 확인하려면 inspect.ismethod()


어떤 함수가 클래스이므로 인스턴스 x의 클래스 이름을 가져와 비교할 수 있습니다.


if(x.__class__.__name__ == 'function'):
     print "it's a function"

사용하는 솔루션 hasattr(obj, '__call__')callable(.)몇 가지 답변에서 언급이 주요 단점이있다 : 두도 반환 TrueA를 클래스와 클래스의 인스턴스에 대한 __call__()방법. 예 :

>>> import collections
>>> Test = collections.namedtuple('Test', [])
>>> callable(Test)
True
>>> hasattr(Test, '__call__')
True

객체가 사용자 정의 함수인지 확인하는 적절한 방법 중 하나는 다음을 사용하는 것입니다 isfunction(.).

>>> import inspect
>>> inspect.isfunction(Test)
False
>>> def t(): pass
>>> inspect.isfunction(t)
True

다른 유형을 확인해야하는 경우 inspect — Inspect live objects를 참조하십시오 .


정확한 기능 검사기

callable 은 아주 좋은 솔루션입니다. 그러나 나는 이것을 John Feminella와 반대되는 방식으로 다루고 싶었습니다. 다음과 같이 처리하는 대신 :

오리 유형 개체의 속성을 확인하는 적절한 방법은 오리 크기의 컨테이너에 맞는지 확인하는 것이 아니라 돌팔이인지 묻는 것입니다. "직접 비교"접근 방식은 내장과 같은 많은 함수에 대해 잘못된 답을 제공합니다.

다음과 같이 처리합니다.

어떤 것이 오리인지 확인하는 적절한 방법은 꽥꽥 거리는 것이 아니라 표면에서 오리처럼 보이는지 확인하는 대신 여러 필터를 통해 실제로 오리인지 확인하는 것입니다.

어떻게 구현할 것인가

'types'모듈에는 함수를 감지하기위한 많은 클래스가 있으며, 가장 유용한 것은 types.FunctionType입니다 . 그러나 메서드 유형, 내장 유형 및 람다 유형과 같은 다른 많은 클래스 도 있습니다. 또한 'functools.partial'객체를 함수로 간주합니다.

함수인지 확인하는 간단한 방법은 이러한 모든 유형에 대해 isinstance 조건을 사용하는 것입니다. 이전에는 위의 모든 클래스를 상속하는 기본 클래스를 만들고 싶었지만 Python이 위 클래스 중 일부에서 상속하는 것을 허용하지 않기 때문에 그렇게 할 수 없습니다.

다음은 어떤 클래스가 어떤 함수를 분류 할 수 있는지에 대한 표입니다.

kinght- 金의 함수 표 kinght- 金의 기능 표 위

그것을하는 코드

자, 이것은 위에서 설명한 모든 작업을 수행하는 코드입니다.

from types import BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType
from functools import partial

def is_function(obj):
  return isinstance(obj, (BuiltinFunctionType, BuiltinMethodType,  FunctionType, MethodType, LambdaType, partial))

#-------------------------------------------------

def my_func():
  pass

def add_both(x, y):
  return x + y

class a:
  def b(self):
    pass

check = [

is_function(lambda x: x + x),
is_function(my_func),
is_function(a.b),
is_function(partial),
is_function(partial(add_both, 2))

]

print(check)
>>> [True, True, True, False, True]

하나의 거짓은 is_function (partial)입니다. 왜냐하면 그것은 함수가 아니라 클래스이기 때문입니다. 그리고 이것은 클래스가 아니라 정확히 함수입니다. 다음은 코드를 사용해 있는 미리보기 입니다.

결론

호출 (OBJ)는 당신이로 가고 싶은 경우 객체가 함수가 있는지 확인하기 위해 사용되는 방법입니다 오리 타이핑 을 통해 절대 .

사용자 정의 is_function (obj) , 아마도 일부 편집을 통해 호출 가능한 클래스 인스턴스를 함수로 계산하지 않고 내장 함수 만 정의 하거나 lambda , def로 정의한 경우 객체가 함수인지 확인하는 데 선호되는 방법입니다. , 또는 부분 .

그리고 나는 그것이 모든 것을 마무리한다고 생각합니다. 좋은 하루 되세요!


Python3에서는 if 가 함수이고 그렇지 않은 경우 type (f) == type (lambda x:x)를 산출 True합니다 . 그러나 나는 덜 임시적인 느낌을 선호한다고 생각합니다 . 하고 싶었지만 작동하지 않습니다.fFalseisinstance (f, types.FunctionType)type (f) is function


이전 답변에 따라 다음과 같이 생각했습니다.

from pprint import pprint

def print_callables_of(obj):
    li = []
    for name in dir(obj):
        attr = getattr(obj, name)
        if hasattr(attr, '__call__'):
            li.append(name)
    pprint(li)

값이 호출 가능하면 코드가 계속해서 호출을 수행하면 호출을 수행하고 catch TypeError합니다.

def myfunc(x):
  try:
    x()
  except TypeError:
    raise Exception("Not callable")

다음은 그것을 확인하는 "반복 방법"입니다. 또한 람다와 함께 작동합니다.

def a():pass
type(a) #<class 'function'>
str(type(a))=="<class 'function'>" #True

b = lambda x:x*2
str(type(b))=="<class 'function'>" #True

이것은 나를 위해 작동합니다.

str(type(a))=="<class 'function'>"

참고 URL : https://stackoverflow.com/questions/624926/how-do-i-detect-whether-a-python-variable-is-a-function

반응형