str.upper
и list.append
обе функции.
str.upper
принимает один аргумент.
>>> str.upper('test')
'TEST'
list.append
принимает два аргумента.
>>> my_list = []
>>> list.append(my_list, 1)
>>> my_list
[1]
str.upper
и list.append
(как и другие функции) также являются не дескрипторами данных с методом __get__
, который в этом контексте имеет два значения:
- Когда вы обращаетесь к функции через класс через точечную запись (
str.upper
, list.append
), вызывается метод __get__
функции (то есть string.upper.__get__
и list.append.__get__
), но он возвращает только саму функцию.
- Когда вы получаете доступ к функции через экземпляр (
my_string.upper
, my_list.append
), вызывается метод __get__
функции, и он возвращает новый вызываемый , действующий как исходная функция, но с тем, что было «перед точкой», автоматически передается в качестве первого аргумента. .
Вот почему вам нужно передавать аргументы 1 - 1 = 0 при вызове my_string.upper()
и аргумент 2 - 1 = 1 при вызове my_list.append(1)
.
>>> 'my_string'.upper()
'MY_STRING'
>>>
>>> my_list = []
>>> my_list.append(1)
>>> my_list
[1]
Вы могли бы даже получить эти измененные вызываемые объекты (методы), явно вызвав __get__
и передав аргумент для привязки (который был до точки) в качестве аргумента.
>>> my_string = 'my_string'
>>> upper_maker = str.upper.__get__(my_string)
>>> upper_maker()
'MY_STRING'
>>>
>>> my_list = []
>>> appender = list.append.__get__(my_list)
>>> appender(1)
>>> my_list
[1]
Наконец, вот короткий пример, демонстрирующий, как экземпляры дескриптора могут определять, к ним ли обращаются через их класс владельца или через экземпляр.
class Descriptor:
def __get__(self, instance, owner_class):
if instance is None:
print('accessed through class')
# list.append.__get__ would return list.append here
else:
print('accessed through instance')
# list.append.__get__ would build a new callable here
# that takes one argument x and that internally calls
# list.append(instance, x)
class Class:
attribute = Descriptor()
Class.attribute # prints 'accessed through class'
instance = Class()
instance.attribute # prints 'accessed through instance'