Como você obtém o xor lógico de duas variáveis ​​no Python?


648

Como você obtém o xor lógico de duas variáveis ​​no Python?

Por exemplo, eu tenho duas variáveis ​​que eu espero que sejam strings. Quero testar se apenas um deles contém um valor True (não é None ou a string vazia):

str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")
if logical_xor(str1, str2):
    print "ok"
else:
    print "bad"

O ^operador parece estar bit a bit e não definido em todos os objetos:

>>> 1 ^ 1
0
>>> 2 ^ 1
3
>>> "abc" ^ ""
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for ^: 'str' and 'str'

3
Como você define "xor" para algumas strings? O que você acha que "abc" ^ "" deve retornar que não?
Mehrdad Afshari

18
Ele deve retornar True, em vez de gerar uma exceção, pois apenas uma das strings é True, conforme definido pelo tipo bool do Python normal.
Zach Hirsch

38
Estou surpreso que o Python não tenha um operador de infixo chamado "xor", que seria a implementação Pythonic mais intuitiva. O uso de "^" é consistente com outras linguagens, mas não é tão legível quanto a maior parte do Python.
Mark E. Haase

13
@MehrdadAfshari A resposta óbvia à sua pergunta é que ela a xor aé definida como (a and not b) or (not a and b)e, portanto a xor b, quando ae bsão cadeias de caracteres, ou quaisquer outros tipos, devem render os (a and not b) or (not a and b)rendimentos.
Kaz

1
A questão é que a documentação é ruim. ^ é "bit a bit exclusivo ou", que literalmente interpretado significa pouco a pouco, não bool por bool. então x'FFFF00 '^ x'FFFF00' deve ser x'000000 '. Ou isso é feito apenas para ocorrer char a char? moldar como números? Precisamos iterar os caracteres da string mais curta para corresponder ao comprimento da string mais longa. Tudo isso deve ser construído dentro.
mckenzm

Respostas:


1188

Se você já está normalizando as entradas para booleanos, então! = É xor.

bool(a) != bool(b)

148
Embora isso seja inteligente e curto, não estou convencido de que esteja limpo. Quando alguém lê essa construção no código, é imediatamente óbvio para eles que esta é uma operação xor? Eu me senti obrigado a adicionar um comentário - um sinal para mim de que estou escrevendo um código pouco claro e tentando me desculpar com um comentário.

47
Talvez "esteja claro que é um XOR?" é a pergunta errada. Estávamos apenas tentando ver se a resposta para duas perguntas é a mesma e pensando em usar o XOR para implementá-la. Por exemplo, se queremos garantir que não estamos comparando maçãs com laranjas, é "se xor (isApple (x), isApple (y))" é realmente mais claro que "if isApple (x)! = IsApple (y)"? Não para mim!
AmigoNico

106
Há um problema ao usar "! =" Como xor. Você provavelmente esperaria que bool (a)! = Bool (b)! = Bool (c) fosse o mesmo que bool (a) ^ bool (b) ^ bool (c). O mesmo acontece com o bool, mas eu recomendaria ^. Para saber o que está acontecendo no primeiro exemplo, procure "encadeamento de operadores".
elmo

19
@elmo: +1 por apontar a diferença e +1 por me ensinar o que é o encadeamento de operadores! Estou no campo que diz que! = Não é tão legível quanto ^.
Mark E. Haase

13
deveria ser bool(a) is not bool(b)?
RNA

485

Você sempre pode usar a definição de xor para computá-la de outras operações lógicas:

(a and not b) or (not a and b)

Mas isso é um pouco detalhado demais para mim e não é particularmente claro à primeira vista. Outra maneira de fazer isso é:

bool(a) ^ bool(b)

O operador xor em dois booleanos é xor lógico (ao contrário de ints, onde é bit a bit). O que faz sentido, já que boolé apenas uma subclasse deint , mas é implementado para ter apenas os valores 0e 1. E xor lógico é equivalente a xor bit a bit quando o domínio está restrito a 0e 1.

Portanto, a logical_xorfunção seria implementada como:

def logical_xor(str1, str2):
    return bool(str1) ^ bool(str2)

Agradecemos a Nick Coghlan na lista de correspondência do Python-3000 .


7
ótimo post, mas de todas as maneiras para nomear seus parâmetros, por que 'str1' e 'str2'?
SingleNegationElimination

1
@Token porque não. Você quer dizer porque eles não são muito pitonicos?
precisa saber é o seguinte

1
@Zach Hirsch Você poderia usar (não aeb) em vez de (be não) para facilitar a leitura ou a definição seria inconsistente com xor.
Orokusaki

10
Você deve colocar o nots primeiro assim, (not b and a) or (not a and b)para que ele retorne a string, se houver, que parece ser a maneira pitônica da função funcionar.
Rjmunro 7/07

2
@TokenMacGuy: O que você estava sugerindo que ele deveria nomeá-los?
user541686

180

Bitwise exclusivo - ou já está embutido no Python, no operatormódulo (que é idêntico ao ^operador):

from operator import xor
xor(bool(a), bool(b))  # Note: converting to bools is essential

3
Era disso que eu precisava. Quando malwares de engenharia reversa muitas vezes as seqüências de caracteres são desconfiguradas até uma operação XOR. Usando este chr (xor (ord ("n"), 0x1A)) = 't'
ril3y

75
Cuidado, isso também é bit a bit: xor(1, 2)retorna 3. Na documentação: xor(a, b) -- Same as a ^ b. Lembre - se de que qualquer coisa importada operatoré apenas uma forma funcional de um operador de infixo interno existente.
askewchan

5
@askewchan: o booltipo sobrecarrega __xor__para retornar booleanos. Vai funcionar muito bem, mas é um exagero quando bool(a) ^ bool(b)faz exatamente a mesma coisa.
Martijn Pieters

@MartijnPieters O ^operador chama __xor__internamente.
Quantum7

5
@ Quantum7: sim, não sei por que você está me dizendo isso. Eu apenas disse que o booltipo implementa o __xor__método especificamente porque o ^chama . O ponto é que bool(a) ^ bool(b)funciona bem, não há necessidade de usar a operator.xor()função aqui.
Martijn Pieters

43

Como Zach explicou, você pode usar:

xor = bool(a) ^ bool(b)

Pessoalmente, sou a favor de um dialeto ligeiramente diferente:

xor = bool(a) + bool(b) == 1

Esse dialeto é inspirado em uma linguagem de diagramação lógica que aprendi na escola, em que "OR" era indicado por uma caixa contendo ≥1(maior ou igual a 1) e "XOR" era indicado por uma caixa contendo =1.

Isso tem a vantagem de implementar corretamente operandos exclusivos ou em múltiplos.

  • "1 = a ^ b ^ c ..." significa que o número de operandos verdadeiros é ímpar. Este operador é "paridade".
  • "1 = a + b + c ..." significa que exatamente um operando é verdadeiro. Isso é "exclusivo ou", significando "um com exclusão dos outros".

12
Portanto, Verdadeiro + Verdadeiro + Falso + Verdadeiro == 3 e 3! = 1, mas Verdadeiro XOR Verdadeiro XOR Verdadeiro XOR Falso XOR Verdadeiro == Verdadeiro. Você pode elaborar a "implementação correta do XOR em vários operandos"?
tzot

3
@tzot Seu exemplo falha, porque, de acordo com a solução da ddaa, você aplica a adição apenas em duas variáveis ​​por vez. Portanto, o caminho certo para escrever tudo isso teria que ser (((((True + True)==1)+False)==1)+True)==1. A resposta dada aqui generaliza totalmente para múltiplos operandos.
quer

6
Além disso, há uma diferença entre um XOR de três vias e um conjunto de dois XORs agrupados por ordem de operações. Então 3-WAY-XOR (A, B, C) não é a mesma coisa que XOR (XOR (A, B), C). E o exemplo de ddaa é o primeiro, enquanto o seu assume o último.
quer

3
@ Mr.F Sua explicação realmente não desculpa essa resposta. Em Python, se você acabou de fazer True + True + False + True, você não conseguir 3, e True + True + False + True == 3dá para trás Trueenquanto True + True + False + True == 1dá de volta False. Em outras palavras, a resposta aqui não generaliza corretamente; para isso, você precisa fazer um trabalho adicional. Enquanto isso, um simples True ^ True ^ False ^ Truefunciona como esperado.
precisa saber é o seguinte

3
@ jpmc26 Não entendi o seu comentário. A abordagem de adição visa generalizar a operação na qual você deseja verificar se exatamente um operando é Trueum XOR de várias regiões. Esta é uma operação diferente da, por exemplo A XOR B XOR ... XOR Z,. Em outras palavras, se você planeja usar a versão baseada em adição, ao enviar os operandos, True + True + False + Truevocê deve esperar que o resultado seja Falseuma vez que mais de um deles é True, o que funciona se a condição verificar == 1.
Ely

26
  • Python logic or:: A or Bretorna Ase bool(A)for True, caso contrário, retornaB
  • Python logic and:: A and Bretorna Ase bool(A)for False, caso contrário, retornaB

Para manter a maior parte desse modo de pensar, minha definição lógica de xor seria:

def logical_xor(a, b):
    if bool(a) == bool(b):
        return False
    else:
        return a or b

Dessa forma, ele pode retornar a, bou False:

>>> logical_xor('this', 'that')
False
>>> logical_xor('', '')
False
>>> logical_xor('this', '')
'this'
>>> logical_xor('', 'that')
'that'

5
Isso parece ruim, ou pelo menos estranho, para mim. Nenhum dos outros operadores lógicos internos retornam um dos três valores possíveis.
Zach Hirsch

2
@Zach Hirsch: É por isso que eu disse "para manter mais de essa maneira de pensar" - uma vez que não há nenhum resultado bom quando ambas são verdadeiras ou falsas
nosklo

A operação lógica deve retornar valor lógico, portanto, o segundo "retorno a ou b" parece estranho, portanto, o segundo retorno deve retornar True.
Denis Barmenkov

9
@ Denis Barmenkov: Bem, observe que os operadores lógicos python ande ornão retornarão valor lógico. 'foo' and 'bar'retorna 'bar'...
nosklo

6
À primeira vista, as 2 respostas anteriores parecem as melhores, mas, pensando bem, essa é realmente a única realmente correta, ou seja, é a única que fornece um exemplo de xorimplementação que é consistente com o built-in ande or. No entanto, é claro, em situações práticas, bool(a) ^ bool(b)ou mesmo a ^ b(se ae bsão conhecidos por serem bool) são mais conciso, claro.
Erik Kaplun

23

Eu testei várias abordagens e not a != (not b)parecia ser o mais rápido.

Aqui estão alguns testes

%timeit not a != (not b)
10000000 loops, best of 3: 78.5 ns per loop

%timeit bool(a) != bool(b)
1000000 loops, best of 3: 343 ns per loop

%timeit not a ^ (not b)
10000000 loops, best of 3: 131 ns per loop

Edit: Os exemplos 1 e 3 acima estão faltando parênteses, portanto o resultado está incorreto. Novos resultados + truth()funcionam como sugerido pelo ShadowRanger.

%timeit  (not a) ^  (not b)   # 47 ns
%timeit  (not a) != (not b)   # 44.7 ns
%timeit truth(a) != truth(b)  # 116 ns
%timeit  bool(a) != bool(b)   # 190 ns

6
Isso é 100 ns da minha vida eu não vou voltar ;-)
Arel

4
Para um tempo intermediário, você pode fazer from operator import truthna parte superior do módulo e testar truth(a) != truth(b). boolser um construtor tem muita sobrecarga inevitável no nível C (ele deve aceitar argumentos como o equivalente *args, **kwargse analisar tuplee dictextraí-los), onde truth(sendo uma função) pode usar um caminho otimizado que não exija tupleou a dicte é executado em cerca de metade do tempo das boolsoluções baseadas (mas ainda mais do que as notsoluções baseadas).
ShadowRanger

9

Segmento de recompensa:

Idéia de ânodo ... Basta tentar a expressão pitônica (pode ser) «não é» para obter o comportamento lógico «xor»

A tabela verdade seria:

>>> True is not True
False
>>> True is not False
True
>>> False is not True
True
>>> False is not False
False
>>>

E para o seu exemplo de string:

>>> "abc" is not  ""
True
>>> 'abc' is not 'abc' 
False
>>> 'abc' is not '' 
True
>>> '' is not 'abc' 
True
>>> '' is not '' 
False
>>> 

Contudo; como indicado acima, depende do comportamento real que você deseja obter sobre algumas cordas, porque cordas não são boleanas ... e ainda mais: se você «Dive Into Python», encontrará «The Peculiar Nature of" e "and" ou "» http://www.diveintopython.net/power_of_introspection/and_or.html

Desculpe meu inglês escrito, não é minha língua nativa.

Saudações.


Eu também uso para lê-lo como "estritamente diferente". Isso ocorre porque algumas linguagens usam para implementar a operação bit a bit da representação binária e pegam o bool da operação bit a bit resultante. Acho que sua resposta é mais "à prova de balas", porque se estende além do espaço booleano.
yucer

Quero dizer o fato de que sua resposta cobre o caso de comparar Nenhum, Falso '', como diferente é o material distintivo. Por exemplo: bool (False)! = Bool (''), no entanto, False não é '' "concorda mais com essa semântica de" estritamente diferente "
yucer 28/03/19

8

Python tem um operador OR exclusivo bit a bit, é ^:

>>> True ^ False
True
>>> True ^ True
False
>>> False ^ True
True
>>> False ^ False
False

Você pode usá-lo convertendo as entradas em booleanos antes de aplicar xor ( ^):

bool(a) ^ bool(b)

(Editado - obrigado Arel)


Sua resposta deve esclarecer que ^é um xor bit a bit (não é lógico como a pergunta). bool(2) ^ bool(3)dá uma resposta diferente de bool(2 ^ 3).
Arel

1
@ Arel Mas não é esse o caso. a ^ bé polimorfo. Se ae bsão boolinstâncias, o resultado também será bool. Esse comportamento dificilmente pode ser chamado de xor "bit a bit".
Alfe

@ Alfe, o ponto importante é que os valores devem ser convertidos em booleanos primeiro. A documentação do Python define ^como bit a bit, mesmo que seja um ponto interessante para o qual os tipos são preservados boole os inttipos. Nota: True ^ 2é 3, demonstrando como é de fato bit a bit.
Arel

@ Arel Sim, o bool ^ intcaso é meio que lançar tudo intprimeiro. Ainda assim, o Python incorporou o ^operador para muitos bits no inte para o bit representado em um bool, então ambos são bit a bit , mas o xor bit a bit para um único bit é apenas o xor lógico para os booleanos.
Alfe

Eu sempre odeio usar esse operador, embora eu entenda que xor, vindo de uma experiência em engenharia, isso me parece instintivamente um poder matemático, ou seja, o 2^3 = pow(2,3)que significa que eu sempre comento explicitamente para evitar confusão.
Nicholas Hamilton

8

Como não vejo a variante simples do xor usando argumentos variáveis ​​e apenas a operação nos valores de Verdadeiro Verdadeiro ou Falso, vou jogá-lo aqui para qualquer um usar. É como observado por outros, bastante (para não dizer muito) direto.

def xor(*vars):
    sum = False
    for v in vars:
        sum = sum ^ bool(v)
    return sum

E o uso também é direto:

if xor(False, False, True, False):
    print "Hello World!"

Como esse é o XOR lógico n-ário generalizado, seu valor de verdade será True sempre que o número de operandos True for ímpar (e não apenas quando exatamente um for True, este é apenas um caso em que o XOR n-ário é True).

Portanto, se você estiver em busca de um predicado n-ário que seja apenas True quando exatamente um de seus operandos for, convém usar:

def isOne(*vars):
    sum = False
    for v in vars:
        if sum and v:
            return False
        else:
            sum = sum or v
    return sum

Para melhorar esta resposta: (bool(False) is False) == True. Você pode apenas usar Falsenessas linhas.
Pathunstrom

7

Exclusive Or é definido da seguinte forma

def xor( a, b ):
    return (a or b) and not (a and b)

2
que retornaria True para xor ('this', '') e, para seguir o caminho do python, deveria retornar 'this'.
nosklo

@nosklo: Aceite o BDFL, por favor, não eu. Como o Python retorna True, esse deve ser o caminho do Python.
S.Lott

2
Quero dizer a consistência com os outros operadores lógicos python - o Python não retorna True quando o faço ('this' ou ''), ele retorna 'this'. Mas na sua função xor ('this', '') retorna True. Ele deve retornar 'this' como o "ou" python interno faz.
nosklo

10
Python ande orfazer curto-circuito. Qualquer xorimplementação não pode causar um curto-circuito; portanto, já existe uma discrepância; portanto, não há razão xorpara operar como and+ ordo.
tzot

7

Às vezes me pego trabalhando com 1 e 0 em vez de valores booleanos True e False. Nesse caso, xor pode ser definido como

z = (x + y) % 2

que possui a seguinte tabela de verdade:

     x
   |0|1|
  -+-+-+
  0|0|1|
y -+-+-+
  1|1|0|
  -+-+-+

7

Sei que é tarde, mas pensei em algo que poderia valer a pena, apenas para documentação. Talvez isso funcione: np.abs(x-y)a idéia é que

  1. se x = True = 1 e y = False = 0, o resultado será | 1-0 | = 1 = True
  2. se x = Falso = 0 e y = Falso = 0, o resultado seria | 0-0 | = 0 = Falso
  3. se x = Verdadeiro = 1 e y = Verdadeiro = 1, o resultado será | 1-1 | = 0 = Falso
  4. se x = Falso = 0 e y = Verdadeiro = 1, o resultado será | 0-1 | = 1 = Verdadeiro

7

Simples, fácil de entender:

sum( (bool(a), bool(b) ) == 1

Se você deseja uma opção exclusiva, ela pode ser expandida para vários argumentos:

sum( bool(x) for x in y ) % 2 == 1

1
sum(map(bool, y)) % 2 == 1
warvariuc

6

Que tal agora?

(not b and a) or (not a and b)

dará ase bfor falso
dará bse afor falso
daráFalse caso contrário

Ou com a expressão ternária do Python 2.5+:

(False if a else b) if b else a

6

Algumas das implementações sugeridas aqui causarão repetidas avaliações dos operandos em alguns casos, o que pode levar a efeitos colaterais indesejados e, portanto, deve ser evitado.

Dito isto, uma xorimplementação que retorna uma Trueou Falseé bastante simples; aquele que retorna um dos operandos, se possível, é muito mais complicado, porque não existe consenso sobre qual operando deve ser o escolhido, especialmente quando há mais de dois operandos. Por exemplo, deve xor(None, -1, [], True)retornar None, []ouFalse ? Aposto que cada resposta aparece para algumas pessoas como a mais intuitiva.

Para o resultado Verdadeiro ou Falso, existem até cinco opções possíveis: retornar primeiro operando (se corresponder ao resultado final em valor, senão booleano), retornar primeiro resultado (se houver pelo menos um, senão booleano), return last operand (if ... else ...), return last match (if ... else ...), ou sempre retorne booleano. No total, são 5 ** 2 = 25 sabores de xor.

def xor(*operands, falsechoice = -2, truechoice = -2):
  """A single-evaluation, multi-operand, full-choice xor implementation
  falsechoice, truechoice: 0 = always bool, +/-1 = first/last operand, +/-2 = first/last match"""
  if not operands:
    raise TypeError('at least one operand expected')
  choices = [falsechoice, truechoice]
  matches = {}
  result = False
  first = True
  value = choice = None
  # avoid using index or slice since operands may be an infinite iterator
  for operand in operands:
    # evaluate each operand once only so as to avoid unintended side effects
    value = bool(operand)
    # the actual xor operation
    result ^= value
    # choice for the current operand, which may or may not match end result
    choice = choices[value]
    # if choice is last match;
    # or last operand and the current operand, in case it is last, matches result;
    # or first operand and the current operand is indeed first;
    # or first match and there hasn't been a match so far
    if choice < -1 or (choice == -1 and value == result) or (choice == 1 and first) or (choice > 1 and value not in matches):
      # store the current operand
      matches[value] = operand
    # next operand will no longer be first
    first = False
  # if choice for result is last operand, but they mismatch
  if (choices[result] == -1) and (result != value):
    return result
  else:
    # return the stored matching operand, if existing, else result as bool
    return matches.get(result, result)

testcases = [
  (-1, None, True, {None: None}, [], 'a'),
  (None, -1, {None: None}, 'a', []),
  (None, -1, True, {None: None}, 'a', []),
  (-1, None, {None: None}, [], 'a')]
choices = {-2: 'last match', -1: 'last operand', 0: 'always bool', 1: 'first operand', 2: 'first match'}
for c in testcases:
  print(c)
  for f in sorted(choices.keys()):
    for t in sorted(choices.keys()):
      x = xor(*c, falsechoice = f, truechoice = t)
      print('f: %d (%s)\tt: %d (%s)\tx: %s' % (f, choices[f], t, choices[t], x))
  print()

5

Muitas pessoas, inclusive eu, precisam de uma xorfunção que se comporte como um circuito xor de entrada n, onde n é variável. (Consulte https://en.wikipedia.org/wiki/XOR_gate ). A seguinte função simples implementa isso.

def xor(*args):
   """
   This function accepts an arbitrary number of input arguments, returning True
   if and only if bool() evaluates to True for an odd number of the input arguments.
   """

   return bool(sum(map(bool,args)) % 2)

E / S de amostra a seguir:

In [1]: xor(False, True)
Out[1]: True

In [2]: xor(True, True)
Out[2]: False

In [3]: xor(True, True, True)
Out[3]: True

5

Para obter o xor lógico de duas ou mais variáveis ​​no Python:

  1. Converter entradas em booleanos
  2. Use o operador bit a bit xor ( ^ou operator.xor)

Por exemplo,

bool(a) ^ bool(b)

Quando você converte as entradas em booleanos, xor bit a bit se torna xor lógico .

Observe que a resposta aceita está errada: != não é a mesma que xor no Python devido à sutileza do encadeamento do operador .

Por exemplo, o xor dos três valores abaixo está errado ao usar !=:

True ^  False ^  False  # True, as expected of XOR
True != False != False  # False! Equivalent to `(True != False) and (False != False)`

(PS: tentei editar a resposta aceita para incluir esse aviso, mas minha alteração foi rejeitada.)


4

É fácil quando você sabe o que o XOR faz:

def logical_xor(a, b):
    return (a and not b) or (not a and b)

test_data = [
  [False, False],
  [False, True],
  [True, False],
  [True, True],
]

for a, b in test_data:
    print '%r xor %s = %r' % (a, b, logical_xor(a, b))

4

Isso obtém o XOR exclusivo lógico para duas (ou mais) variáveis

str1 = raw_input("Enter string one:")
str2 = raw_input("Enter string two:")

any([str1, str2]) and not all([str1, str2])

O primeiro problema dessa configuração é que ela provavelmente percorre a lista inteira duas vezes e, no mínimo, verifica pelo menos um dos elementos duas vezes. Portanto, isso pode aumentar a compreensão do código, mas não leva à velocidade (que pode diferir de maneira insignificante dependendo do seu caso de uso).

O segundo problema com essa instalação é que ele verifica a exclusividade, independentemente do número de variáveis. Isso pode ser visto a princípio como um recurso, mas o primeiro problema se torna muito mais significativo à medida que o número de variáveis ​​aumenta (se é que o fazem).


4

Xor está ^em Python. Retorna:

  • Um xor bit a bit para ints
  • Xor lógico para bools
  • Uma união exclusiva para conjuntos
  • Resultados definidos pelo usuário para classes que implementam __xor__ .
  • TypeError para tipos indefinidos, como seqüências de caracteres ou dicionários.

Se você pretende usá-los em cadeias de qualquer maneira, convertê-las em booltorna sua operação inequívoca (você também pode querer dizer set(str1) ^ set(str2)).



3

É assim que eu codificaria qualquer tabela de verdade. Para o xor em particular, temos:

| a | b  | xor   |             |
|---|----|-------|-------------|
| T | T  | F     |             |
| T | F  | T     | a and not b |
| F | T  | T     | not a and b |
| F | F  | F     |             |

Basta olhar para os valores T na coluna de resposta e juntar todos os casos verdadeiros com lógica ou. Portanto, essa tabela de verdade pode ser produzida nos casos 2 ou 3. Portanto,

xor = lambda a, b: (a and not b) or (not a and b)

-6

Podemos encontrar facilmente xor de duas variáveis ​​usando:

def xor(a,b):
    return a !=b

Exemplo:

xor (Verdadeiro, Falso) >>> Verdadeiro


1
ou xor("hey", "there")>>> Verdade, mas não é isso que queremos #
Mayou36
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.