Как правило, код <type>(arg1=value1) заменяется на код <type>(attr1=value1) во время case в операторе сопоставления . Это позволяет делать очень интересные и сложные снимки.
Например, мы можем спросить: «Есть ли у моего экземпляра атрибут под названием «sort», если да, то зафиксируйте его»:
match [1,2,3]:
case list(sort=f): # this isn't a call, it is an attr-capture statement
print(f)
Поскольку первым (и единственным) позиционным аргументом экземпляра списка являются значения списка, вы также можете захватывать эти элементы:
match [1,2,3]:
case list((x,*y),sort=f): # here we are capturing the 'attr' called 'sort' as 'f'
print(x,y,f)
Аналогичным образом вы можете указать совпадающие значения вместо того, чтобы фиксировать их в переменных:
g = list.sort
match [1,2,3]:
case list((1,*y),sort=g): # here we ask if the attr 'sort' is the same as 'g'
print(y)
Однако теперь меня смущает следующее:
match [1,2,3]:
case list(x,sort=list.sort): # fails to match, but why???
print(x)
Я бы подумал, что это не удастся, потому что list.sort означает нечто иное, чем указание «функции сортировки списка». Возможно, sort=list.sort означает «есть ли у меня атрибут под названием «сортировка», который сам имеет тип «список», который также имеет атрибут под названием «сортировка»». Итак, я попробовал:
match [1,2,3]:
case list.sort: # also fails, why?
print('ya')
Итак, list.sort не означает, что мне нужен список типов с атрибутом сортировки. Итак, я попробовал:
match list.sort:
case list.sort: # does match, wait, what?
print('ya')
Это работает. Итак, list.sort во время case означает использование функции sort типа list, но тогда почему list(sort=list.sort) не удалось?
Пример захвата атрибута «y» и сопоставления атрибута «x»:
class P:
def __init__(self,a,b):
self.x,self.y = a+b,a-b
match P(5,6):
case P(x=11,y=a): # a is a new variable, 11 is a match
print(a)
list.sort — это функциональный объект. Он никогда не будет соответствовать объекту списка, но, конечно, он может соответствовать самому себе.
@jonrsharpe, но он не перезаписывает другие значения атрибутов (1,...) в кортеже. вы можете проверить это для пользовательского класса, установив для атрибута значение «7», а затем указав его вместо его захвата.
@TimRoberts верно, но тогда почему «список(sort=list.sort)» не удается захватить?
Как бы вы переопределили значение 1?! Я не понимаю, почему вы думаете, что sort=f будет захватывать атрибут sort, соответствующий f (правильно, как показывают ваши выходные данные), но решаете, что sort=g делает что-то совершенно другое.
@jonrsharpe именно так работает документация. указание того, что уже существует, означает «сопоставление», указание новой переменной означает «захват». Я добавлю пример.
Но вы можете продемонстрировать, например. g = "not the list.sort method" что после матча снова <built-in method sort ..., хотя [1, 2, 3].sort совсем не та строка. 11 не является существующей переменной, идентификатором; это ценность. list.sort не является идентификатором, поэтому рассматривается как значение.
@jonrsharpe Боже мой, вы не можете использовать определенные переменные при захвате. Я никогда этого не осознавал. Что это говорит о «списке (сортировка = список. сортировка)»? Что оно делает?
@jonrsharpe, вы говорите, что list.sort рассматривается как значение, но, похоже, это не так, поскольку «list(sort=list.sort)» не соответствует экземпляру [1,2,3], хотя его атрибут "sort" на самом деле является "list.sort".
«it's attr «sort» на самом деле является «list.sort»» — list.sort — это <method 'sort' of 'list' objects>, а не <built-in method sort of list object at 0x...>. Если вы учли, например. l = [1, 2, 3] и использовали list(sort=l.sort), связанный метод того же экземпляра, вы увидите, что он соответствует этому случаю.
@jonsharpe я никогда не знал, что методы класса — это не те же методы, что и экземпляры, так всегда было?
Пожалуйста, вносите пояснения с помощью правок, а не комментариев, удаляйте и отмечайте устаревшие комментарии. Комментарии не для того, чтобы задавать новые вопросы. Задайте в своем посте 1 (конкретный, не повторяющийся) вопрос. Если вы получаете что-то, чего не ожидаете, когда приводите минимально воспроизводимый пример , скажите, чего вы ожидали и почему это обосновано авторитетной документацией; в противном случае вы просто просите переписать документацию без каких-либо подробностей о том, что вы в ней делаете или чего не понимаете или понимаете неправильно. Как задать вопрос Справочный центр






list.sort — это дескриптор, поэтому он не будет соответствовать sort=, который будет методом или функцией.
Вы можете видеть, что тип f является встроенным методом:
match [1,2,3]:
case list(x,*y), sort=f): # inspect the capture of `sort` as `f`
print('match', f) # match <built-in method sort of list object at 0x104d94c80>
Но тип list.sort не таков:
>>> type(list.sort)
method_descriptor
>>> list.sort is [1,2,3].sort
False
Но если вы используете метод из того же экземпляра списка, это работает:
foo = [1,2,3]
match foo:
case list((x, *y), sort=foo.sort):
print('matched')
Но для меня нет особого смысла сопоставлять атрибут sort, поскольку он различен для каждого экземпляра списка:
>>> x = [1,2,3]
>>> y = [1,2,3]
>>> x.sort is y.sort
False
>>> x.sort == y.sort
False
Спасибо! я никогда не осознавал, что [1,2,3].sort is list.sort — ложь. Я всегда думал об экземплярах, вызывающих методы, как о вызовах методов, которые я определил в классе, я никогда не замечал, что Python разделяет их. так было всегда?
list.sort — обычная функция. [1,2,3].sort — связанный метод (экземпляр types.MethodType, который обертывает как [1,2,3], так и list.sort).
Другая вещь, которую здесь, вероятно, следует охватить, — это фундаментальное различие между sort=f (идентификатор -> привязывает значение) и sort=list.sort (не идентификатор -> другой уровень шаблона).
Говоря языком match, f — это шаблон захвата, а list.sort — это шаблон значения.
@chepner да, но, похоже, это не уникально для list, похоже, что в любом class P: pass тогда P.__init__ is P().__init__ неверно.
Во второй строке первого фрагмента кода есть несовпадающие круглые скобки.
Вы можете подумать о [1,2,3].sort что-то вроде list.sort.__get__([1,2,3], list).
Связанные методы всегда представляли собой разные объекты для каждого экземпляра. Однако функции и статические методы разные. В Python2 несвязанные методы также отличались от функций. В Python3 несвязанные методы — это просто функции. Если бы вы выполнили ту же самую проверку со статическим методом, она фактически работала бы так, как ожидалось, поскольку статические методы класса — это тот же объект, что и статический метод в каждом экземпляре.
Другим элементом является понимание того, что происходит, когда вы используете идентификатор (например, f) в операторе match вместо местоположения/значения (name.name или "literal value"), но я думаю, что другие это уже рассмотрели. Для полноты и авторитетности источника, из PEP 636: «голое имя без точек) всегда будет интерпретироваться как шаблон захвата».
@sytech да, я начинаю это понимать. Сопоставление регистра — это что-то вроде расширенной формы распаковки, например [(x,y),z] = [(1,2),(3,4)] ; так что это имеет смысл. вероятно, именно поэтому в коде есть часть «if», чтобы вы могли записать и затем сравнить, если необходимо.
«здесь мы спрашиваем, совпадает ли атрибут 'sort' с 'g'» - я не думаю, что это правда, все, что
gбыло раньше, затеняется захватом методаsortсовпадения.