Shared posts

17 Oct 11:14

Pegadinha em valores default em funções

by stummjr

Se você é desenvolvedor Python, já deve ter visto muitas funções que definem valores padrão para alguns de seus argumentos. Por exemplo:

def power(base, exp=2):
    return base**exp

É bem comum usarmos esse artifício quando queremos que determinado parâmetro tenha um valor mesmo que o chamador não tenha passado valor algum para ele. Isso funciona muito bem, porém, pode gerar uma certa confusão quando o tipo do valor default do parâmetro em questão for mutável. Veja o trecho de código abaixo:

def func(valor, seq=[]):
    seq.append(valor)
    return seq

print func(10)
print func(20)
print func(30)

Antes de executar o código acima, responda: o que será impresso pelo código acima?

Se você respondeu

[10]
[20]
[30]

você está errado, pois o resultado é:

[10]
[10, 20]
[10, 20, 30]

Observe que, na segunda chamada à função func(), a lista seq manteve o valor 10 como elemento e então adicionou o valor 20 ao seu final. Mas por quê, se seq possui uma lista vazia [] como valor default? Este valor não deveria ser atribuído a seq a cada chamada de função?

A resposta é, como tudo em Python, consistente com a linguagem. Em Python, valores default de parâmetros são avaliados somente no momento em que a função estiver sendo avaliada (em sua definição), e não a cada chamada à mesma.

Ao encontrar a palavra-chave def, o interpretador Python avalia a expressão seguinte como uma função e então cria em memória um objeto function referente à função definida. Assim, a atribuição seq=[] é feita pelo interpretador nesse momento, e não a cada vez que func for chamada.

Vamos ver o que acontece: quando func é chamada pela primeira vez, a lista referenciada por seq possui o valor []. Então, dentro da função é feito um append em seq do valor recebido como parâmetro. Como seq é uma referência para um objeto mutável (uma lista), a lista referenciada por seq é quem tem adicionada a si o valor passado como parâmetro. Na chamada seguinte, seq continua apontando para o mesmo objeto lista, que agora possui um elemento (o valor 10) e então o valor 20 será, dentro da função, adicionado ao final da lista referenciada por seq. Na última chamada, é adicionado o valor 30 ao final da lista apontada por seq.

O que deve ser lembrado sempre é que valores default para parâmetros em uma função são avaliados somente na definição da mesma, e não a cada chamada.

Como driblar isso?

Se você precisar que um parâmetro tenha o valor [] quando o chamador não passar valor algum a ele, você pode fazer o seguinte:


def func(valor, seq=None):
    if seq is None:
        # chamador não forneceu valor para seq
        seq = []
    seq.append(valor)
    return seq

Leia mais

Detalhes como o apresentado neste post são tratadas em alguns livros, como os excelentes:

Obrigado ao Elias Dorneles pela revisão!


20 Jun 21:45

The Cookie Clearinghouse

by Brendan Eich
Eliasdorneles

muito bom que alguém esteja trabalhando nisso.

As you may recall from almost six weeks ago, we held the Safari-like third-party cookie patch, which blocks cookies set for domains you have not visited according to your browser’s cookie database, from progressing to Firefox Beta, because of two problems:

False positives. For example, say you visit a site named foo.com, which embeds cookie-setting content from a site named foocdn.com. With the patch, Firefox sets cookies from foo.com because you visited it, yet blocks cookies from foocdn.com because you never visited foocdn.com directly, even though there is actually just one company behind both sites.

False negatives. Meanwhile, in the other direction, just because you visit a site once does not mean you are ok with it tracking you all over the Internet on unrelated sites, forever more. Suppose you click on an ad by accident, for example. Or a site you trust directly starts setting third-party cookies you do not want.

Our challenge is to find a way to address these sorts of cases. We are looking for more granularity than deciding automatically and exclusively based upon whether you visit a site or not, although that is often a good place to start the decision process.

The logic driving us along the path to a better default third-party cookie policy looks like this:

  1. We want a third-party cookie policy that better protects privacy and encourages transparency.
  2. Naive visited-based blocking results in significant false negative and false positive errors.
  3. We need an exception management mechanism to refine the visited-based blocking verdicts.
  4. This exception mechanism cannot rely solely on the user in the loop, managing exceptions by hand. (When Safari users run into a false positive, they are advised to disable the block, and apparently many do so, permanently.)
  5. The only credible alternative is a centralized block-list (to cure false negatives) and allow-list (for false positives) service.

I’m very pleased that Aleecia McDonald of the Center for Internet and Society at Stanford has launched just such a list-based exception mechanism, the Cookie Clearinghouse (CCH).

Today Mozilla is committing to work with Aleecia and the CCH Advisory Board, whose members include Opera Software, to develop the CCH so that browsers can use its lists to manage exceptions to a visited-based third-party cookie block.

The CCH proposal is at an early stage, so we crave feedback. This means we will hold the visited-based cookie-blocking patch in Firefox Aurora while we bring up CCH and its Firefox integration, and test them.

Of course, browsers would cache the block- and allow-lists, just as we do for safe browsing. I won’t try to anticipate or restate details here, since we’re just starting. Please see the CCH site for the latest.

We are planning a public “brown bag” event for July 2nd at Mozilla to provide an update on where things stand and to gather feedback. I’ll update this post with details as they become available (UPDATE: details are here), but I wanted to share the date ASAP.

/be