Забавно, что вы должны спросить об этом, я был немного удивлен другим использованием этого в документации django ранее сегодня:
def upper_case_name(obj):
return ("%s %s" % (obj.first_name, obj.last_name)).upper()
upper_case_name.short_description = 'Name'
# !!! another occurrence of a "method attribute," an attribute
# assigned to a function object.
class PersonAdmin(admin.ModelAdmin):
list_display = (upper_case_name,)
Итак, по сути, это означает, что определения функций являются типом объекта. Более знакомый способ сказать это может быть:
>>> def myfunc():
... return "myvalue"
# 'myfunc' is now an object of type 'function' in the local scope. observe:
>>> type(myfunc)
<type: 'function'>
# you can, of course call __call__ on 'myfunc':
>>> myfunc()
"myvalue"
>>> myfunc.__call__()
"myvalue"
# and because 'myfunc' is also a normal object, you can define attributes on it.
myfunc.someattribute = 'somevalue'
myfunc.is_a_function = True
myfunc.takes_args = False
Итак, ваш вопрос имеет какое-то отношение к идее, что python - это "объекты на всем пути вниз", то есть, что все в python является объектом.
Теперь, почему это полезно? Предположим, вы хотите собрать и использовать некоторые метаданные для набора функций (или методов), которые вы пишете:
from operator import attrgetter
def add(x, y):
return x + y
def subtract(x, y):
return x - y
def get_attribute_value(obj, attr):
return attrgetter(attr)(obj)
add.takes_args = True
add.number_of_args = 2
add.type_of_args = [int, int]
add.uses_black_magic = False
subtract.takes_args = True
subtract.number_of_args = 2
subtract.type_of_args = [int, int]
subtract.uses_black_magic = False
get_attribute_value.takes_args = True
get_attribute_value.number_of_args = 2
get_attribute_value.type_of_args = [object, str]
get_attribute_value.uses_black_magic = True
Затем вы можете использовать эти «атрибуты метода» полезным способом:
def perform_function_checks(function_list):
for afunc in function_list:
if getattr(afunc, 'takes_args'):
print "function '%s' takes args! how unusual!" % (afunc.__name__,)
if getattr(afunc, 'number_of_args'):
print "function '%s' takes %s args." % (afunc.__name__, afunc.number_of_args)
if getattr(afunc, 'type_of_args'):
print "function '%s' takes %s args: %s" (afunc.__name__, len(afunc.type_of_args), [", and ".join(str(item)) for item in afunc.type_of_args])
if getattr(afunc, 'uses_black_magic'):
print "oh no! function '%s' uses black magic!" % (afunc.__name__,)
perform_function_checks([add, subtract, get_attribute_value])
# prints:
# function 'add' takes args! how unusual!
# function 'add' takes 2 args.
# function 'add' takes 2 args: <type 'int'>, and <type 'int'>
# function 'subtract' takes args! how unusual!
# function 'subtract' takes 2 args.
# function 'subtract' takes 2 args: <type 'int'>, and <type 'int'>
# function 'get_attribute_value' takes args! how unusual!
# function 'get_attribute_value' takes 2 args.
# function 'get_attribute_value' takes 2 args: <type 'object'>, and <type 'str'>
# oh no! function 'get_attribute_value' uses black magic!
Теперь, конечно, вышеприведенное приведено только для иллюстративных целей. Если вы на самом деле пытались сделать этот тип самоанализа для функций и объектов, вы, вероятно, захотите использовать модуль 'inspect' вместо добавления своего собственного bizarro. метаданные: http://docs.python.org/library/inspect.html
Для получения дополнительной информации по этой теме, я бы порекомендовал этот пост:
http://www.cafepy.com/article/python_types_and_objects/python_types_and_objects.html
- РЕДАКТИРОВАТЬ:
извините, я не рассмотрел вашу "реализацию, которая позволяет вызывать атрибуты метода" в приложении № 2.
В вашем примере в этой дискуссии есть немного красной сельди. Там происходит то, что кто-то использует декоратор @property для украшения метода, чтобы он выглядел как свойство (a.k.a. 'attribute'). Рассмотрим этот пример:
# let's define a simple class
class Foo():
# and a "normal" attribute
an_attribute = 'a value'
# now a method that we'll decorate with the @property decorator
@property
def what_kind(self):
return str(self.__class__.__name__)
# now, instances of our Foo class will have the attribute '.what_kind'.
>>> bar = Foo()
# bar is now an instance of foo.
>>> bar.an_attribute
"a value"
# and finally our decorated method:
>>> bar.what_kind
"Foo"
Обратите внимание, что нам не нужно было вызывать 'what_kind' выше, чтобы вернуть значение. Я думаю, что все, что делает @property decorator - это автоматически вызывает .__call__()
Итак, автор этого поста заставляет django показывать, что вы просто добавляете в класс «обычный старый» атрибут, когда на самом деле .short_description и .votes_today на самом деле являются методами.
Вот дополнительная информация о декораторе / функции @property (которая встроена в BTW, поэтому вам не нужно ее импортировать):
http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/
- РЕДАКТИРОВАТЬ: исправлено несколько проблем с разметкой и опечатка.