Как сгенерировать именованный вектор (i.e: & ldquo; 0 & rdquo; = & ldquo; blue & rdquo;) без жесткого кодирования в R [дубликат]

Python: Mutable Default Argument

Аргументы по умолчанию получают оценку во время компиляции функции в объект функции. При использовании этой функции, несколько раз с помощью этой функции, они являются и остаются одним и тем же объектом.

Когда они изменяются, когда они мутируются (например, добавляя к нему элемент), они остаются мутированными по последовательным вызовам.

Они остаются мутированными, потому что каждый раз они являются одним и тем же объектом .

Эквивалентный код:

Поскольку список связан с функцией, когда объект функции компилируется и инстанцируется, это:

def foo(mutable_default_argument=[]): # make a list the default argument
    """function that uses a list"""

почти точно эквивалентно этому:

_a_list = [] # create a list in the globals

def foo(mutable_default_argument=_a_list): # make it the default argument
    """function that uses a list"""

del _a_list # remove globals name binding

Демонстрация

Вот демонстрация - вы можете проверить, что они являются одним и тем же объектом каждый раз, когда они ссылаются на

  • , увидев, что список создан до того, как функция завершила компиляцию объекту функции,
  • , заметив, что идентификатор один и тот же каждый раз, когда список ссылается,
  • , наблюдая, что список остается, когда функция, которая его использует, называется второй раз,
  • , наблюдая порядок, в котором вывод печатается из источника (который я удобно пронумеровал для вас):

example.py

print('1. Global scope being evaluated')

def create_list():
    '''noisily create a list for usage as a kwarg'''
    l = []
    print('3. list being created and returned, id: ' + str(id(l)))
    return l

print('2. example_function about to be compiled to an object')

def example_function(default_kwarg1=create_list()):
    print('appending "a" in default default_kwarg1')
    default_kwarg1.append("a")
    print('list with id: ' + str(id(default_kwarg1)) + 
          ' - is now: ' + repr(default_kwarg1))

print('4. example_function compiled: ' + repr(example_function))


if __name__ == '__main__':
    print('5. calling example_function twice!:')
    example_function()
    example_function()

и работает это с python example.py:

1. Global scope being evaluated
2. example_function about to be compiled to an object
3. list being created and returned, id: 140502758808032
4. example_function compiled: 
5. calling example_function twice!:
appending "a" in default default_kwarg1
list with id: 140502758808032 - is now: ['a']
appending "a" in default default_kwarg1
list with id: 140502758808032 - is now: ['a', 'a']

Означает ли это нарушение принципа «Наименьшее удивление»?

Этот порядок выполнения часто путает новых пользователей Python. Если вы понимаете модель исполнения Python, это становится вполне ожидаемым.

Обычная инструкция для новых пользователей Python:

Но поэтому обычная инструкция для новых пользователей заключается в том, чтобы вместо этого создать свои аргументы по умолчанию:

def example_function_2(default_kwarg=None):
    if default_kwarg is None:
        default_kwarg = []

Это использует None singleton как объект-дозор, чтобы сообщить функции, есть ли у нас аргумент, отличный от значения по умолчанию. Если мы не получаем никакого аргумента, то мы действительно хотим использовать новый пустой список [] в качестве значения по умолчанию.

Как говорится в разделе в разделе управления потоком :

Если вы не хотите, чтобы по умолчанию были разделены между последующими вызовами, вы можете написать такую ​​функцию, как это:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L
45
задан SFun28 23 September 2011 в 23:20
поделиться

6 ответов

Соглашение об именовании векторных элементов такое же, как со списками:

newfunc <- function(A=1, B=2) { body}  # the parameters are an 'alist' with two items

Если вместо этого вы хотели, чтобы это был параметр, который был именованным вектором (вид функции, которая обрабатывала бы аргументы apply):

newfunc <- function(params =c(A=1, B=2) ) { body} # a vector wtih two elements

Если вместо этого вы хотели, чтобы это был параметр, который был именованным списком:

newfunc <- function(params =list(A=1, B=2) ) { body} 
    # a single parameter (with two elements in a list structure
16
ответ дан 42- 21 August 2018 в 00:05
поделиться
  • 1
    Ах! Я никогда не пробовал эти обозначения, потому что думал, что он ограничен списками и data.frames – SFun28 23 September 2011 в 23:32
  • 2
    Этот ответ содержит ответ из @joran , но его трудно сказать, потому что он скрыт здесь: function(params= ...) { body } – The Red Pea 6 September 2015 в 20:33
  • 3
    Я думаю, мы читаем вопрос по-другому. Я думал, что речь идет о параметрах функции. joran думал, что речь идет о списке имен или элементов вектора. Это своего рода различие без большой разницы, потому что параметры функции являются типом списка. – 42- 7 September 2015 в 03:56
  • 4
    На самом деле я не понимаю этого ответа. Может быть, конкретный случай для body и того, как использовать newfunc для получения запрошенной структуры данных, будет полезен. – U. Windl 24 October 2017 в 12:14
  • 5
    Я ответил на вопрос (который не запрашивал вариант использования и скорее попросил синтаксических возможностей.) Если вам это нужно для конкретного действия, вы должны отправить вопрос с данными и сказать, что вам нужно сделать. – 42- 25 October 2017 в 23:53

Для этой цели создана функция setNames(). Как описано в Advanced R и ?setNames:

test <- setNames(c(1, 2), c("A", "B"))
50
ответ дан Aaron Schumacher 21 August 2018 в 00:05
поделиться

Как насчет:

 c(A = 1, B = 2)
A B 
1 2 
34
ответ дан joran 21 August 2018 в 00:05
поделиться

magrittr предлагает хорошее и чистое решение.

result = c(1,2) %>% set_names(c("A", "B"))
print(result)
A B 
1 2

Вы также можете использовать его для преобразования data.frames в векторы.

df = data.frame(value=1:10, label=letters[1:10])
vec = extract2(df, 'value') %>% set_names(df$label)
vec
 a  b  c  d  e  f  g  h  i  j 
 1  2  3  4  5  6  7  8  9 10
df
    value label
 1      1     a
 2      2     b
 3      3     c
 4      4     d
 5      5     e
 6      6     f
 7      7     g
 8      8     h
 9      9     i
 10    10     j
2
ответ дан sginzel 21 August 2018 в 00:05
поделиться

... как побочная заметка, функция structure позволяет вам устанавливать ВСЕ атрибуты, а не только имена:

structure(1:10, names=letters[1:10], foo="bar", class="myclass")

, которые будут генерировать

 a  b  c  d  e  f  g  h  i  j 
 1  2  3  4  5  6  7  8  9 10 
attr(,"foo")
[1] "bar"
attr(,"class")
[1] "myclass"
50
ответ дан Tommy 21 August 2018 в 00:05
поделиться
0
ответ дан Karl Baker 31 October 2018 в 19:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: