Bir değişkenim var ve bunun bir işleve işaret edip etmediğini bilmek istiyorum.
Akla gelen ilk yöntem isinstance kullanmak. Şöyle bir şey yapabileceğimizi düşünebiliriz:
>>> isinstance(x, function)
Ama bu kodd parçası aşağıdaki hatayı verir:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'function' is not defined
Peki bu değişkenin bir fonksiyon olduğunu nasıl anlayabiliriz?
Eğer Python 2.x veya Python 3.2+ ile çalışıyorsak callable()'i
kullanabiliriz. Bu yöntem kullanım dışı bırakılmıştı, ancak şimdi tekrar kullanımda. Bu yüzden biz de tekrar kullanabiliriz. Bununla ilgili tartışmayı buradan okuyabilirsiniz: http://bugs.python.org/issue10518.
Şu şekilde yapıyoruz:
callable(obj)
Bu Python 3.x içinse, ancak 3.2’den önceyse, nesnenin bir __call__
özniteliği olup olmadığını kontrol edebiliriz.
hasattr(obj, '__call__')
Genellikle önerilen types.FunctionTypes
veya inspect.isfunction
yaklaşımları (aslında her ikisi de aynı şeyi yapar) bir dizi uyarıyla birlikte gelir. Mesela, Python’da olmayan işlevler için False
döndürürler. Örneğin, yerleşik işlevlerin çoğu Python’da değil C’de oluşturulur, bu nedenle bunlar da False
dönerler:
>>> isinstance(open, types.FunctionType)
False
>>> callable(open)
True
bu yüzden şaşırtıcı sonuçlar verebilirler.
callable()
üzerinde biraz daha duralım.
Görünüşe göre, Python 3.2’de geri dönen callable()
‘in yerini başka bir yöntem tutmuyor: callable()
, test edilen nesnenin tp_call
özelliğini kontrol eder. Bunun düz bir Python eşleniği yoktur. Önerilen testlerin çoğu çoğu zaman doğrudur:
>>> 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
Sınıfı biraz değiştirelim, önce __call__
‘ı silelim. Sonra, biraz heyecan kaktalım ve örneğe bir sahte __call__
ekleyelim.
>>> del Spam.__call__
>>> can_o_spam.__call__ = lambda *args: 'OK?'
Bu ddurumda bunun gerçekten çağrılabilir olmadığına dikkat edin:
>>> can_o_spam()
Traceback (most recent call last):
...
TypeError: 'Spam' object is not callable
Şimdi callable
ve hasattr
yaklaşımlarını inceleyelim. callable()
ile test edersek olması gereken sonucu alırız:
>>> callable(can_o_spam)
False
Ama hasattr
yanlış sonuç verir:
>>> hasattr(can_o_spam, '__call__')
True
Peki isinstance()
? Bu da yanlış sonuç verir:
>>> isinstance(can_o_spam, collections.Callable)
True
Sonuç? callable()
en doğru sonucu verecektir.