objeto nulo em Python?

1193

Como me refiro ao objeto nulo no Python?

Lagarto
fonte

Respostas:

1629

No Python, o objeto 'nulo' é o singleton None.

A melhor maneira de verificar as coisas para "Noneness" é usar o operador de identidade is:

if foo is None:
    ...
Ben James
fonte
126
E a razão para a escolha egg is Nonesobre egg == None: O último pode ser sobrecarregado, e é provável que quebrar quando comparando objeto válido com Nenhum (depende de como ele é implementado, mas você não espera que todos a tomar comparações com None em conta, não é?) , enquanto issempre funciona da mesma maneira.
94
por que os designers de python não escolheram "null". Só tem que ser diferente, não é! ;)
Vidar 26/03
35
@Vidar 'None' não é a falta de um objeto (como 'null' é, uma referência nula), é um objeto real. Você nunca receberá um objeto 'None' passando para um objeto que é de um tipo de coisa diferente de 'NoneType'. Também não é um conceito de linguagem. Não está embutido no Python, é parte da biblioteca padrão do Python. Nenhum! == (ahem) Nulo
Rushyo
11
@ naught101 Não serviria para nada; como não há conceito de ponteiros. Se você estiver usando a biblioteca ctypes, None será usado como sinônimo de endereço zero, mas ainda não existe o conceito de linguagem de uma 'referência nula'. No Python, você sempre fazia referência a algum tipo de objeto, mesmo que esse objeto seja Nenhum. Eu suspeito que isso simplifique bastante o idioma.
Rushyo 02/09
5
ótima apresentação explicando o 'erro de bilhão de dólares' que é a referência nula: infoq.com/presentations/… . Outras opções em vez de nulo são os tipos Opções ou Talvez (personalizado).
Michael Trouw
135

NoneNulo do Python?

Não existe nullno Python, mas sim None. Como já foi dito, a maneira mais precisa de testar se algo foi dado Nonecomo valor é usar o isoperador de identidade, que testa se duas variáveis ​​se referem ao mesmo objeto.

>>> foo is None
True
>>> foo = 'bar' 
>>> foo is None
False

O básico

Existe e só pode haver um None

Noneé a única instância da classe NoneTypee qualquer tentativa adicional de instanciar essa classe retornará o mesmo objeto, o que cria Noneum singleton. Os recém-chegados ao Python costumam ver mensagens de erro que mencionam NoneTypee se perguntam o que é. É minha opinião pessoal que essas mensagens poderiam simplesmente ser mencionadas Nonepelo nome porque, como veremos em breve, Nonedeixa pouco espaço para a ambiguidade. Portanto, se você vir alguma TypeErrormensagem que mencione que NoneTypenão pode ou não pode fazer isso, saiba que é simplesmente aquela Noneque estava sendo usada de uma maneira que não pode.

Além disso, Noneé uma constante interna, assim que você inicia o Python, ele está disponível para uso em qualquer lugar, seja no módulo, na classe ou na função. NoneTypepor outro lado, não, você precisa obter uma referência a ele primeiro consultando Nonesua classe.

>>> NoneType
NameError: name 'NoneType' is not defined
>>> type(None)
NoneType

Você pode verificar Nonea singularidade da função de identidade do Python id(). Retorna o número único atribuído a um objeto, cada objeto possui um. Se o id de duas variáveis ​​for o mesmo, elas apontam de fato para o mesmo objeto.

>>> NoneType = type(None)
>>> id(None)
10748000
>>> my_none = NoneType()
>>> id(my_none)
10748000
>>> another_none = NoneType()
>>> id(another_none)
10748000
>>> def function_that_does_nothing(): pass
>>> return_value = function_that_does_nothing()
>>> id(return_value)
10748000

None não pode ser substituído

Em uma versão muito mais antiga do Python (anterior à 2.4), era possível reatribuir None, mas não mais. Nem mesmo como um atributo de classe ou nos limites de uma função.

# In Python 2.7
>>> class SomeClass(object):
...     def my_fnc(self):
...             self.None = 'foo'
SyntaxError: cannot assign to None
>>> def my_fnc():
        None = 'foo'
SyntaxError: cannot assign to None

# In Python 3.5
>>> class SomeClass:
...     def my_fnc(self):
...             self.None = 'foo'
SyntaxError: invalid syntax
>>> def my_fnc():
        None = 'foo'
SyntaxError: cannot assign to keyword

Portanto, é seguro assumir que todas as Nonereferências são iguais. Não há "costume" None.

Para testar o Noneuso do isoperador

Ao escrever o código, você pode tentar testar o Noneness dessa maneira:

if value==None:
    pass

Ou para testar falsidade como esta

if not value:
    pass

Você precisa entender as implicações e por que geralmente é uma boa idéia ser explícito.

Caso 1: testando se um valor é None

por que fazer isso

value is None

ao invés de

value==None

O primeiro é equivalente a:

id(value)==id(None)

Considerando que a expressão value==Noneé de fato aplicada assim

value.__eq__(None)

se o valor realmente for None, você obterá o que esperava.

>>> nothing = function_that_does_nothing()
>>> nothing.__eq__(None)
True

Na maioria dos casos comuns, o resultado será o mesmo, mas o __eq__()método abre uma porta que anula qualquer garantia de precisão, pois pode ser substituída em uma classe para fornecer um comportamento especial.

Considere esta classe.

>>> class Empty(object):
...     def __eq__(self, other):
...         return not other

Então você experimenta Nonee funciona

>>> empty = Empty()
>>> empty==None
True

Mas também funciona na string vazia

>>> empty==''
True

E ainda

>>> ''==None
False
>>> empty is None
False

Caso 2: usando Nonecomo um booleano

Os dois testes a seguir

if value:
    # do something

if not value:
    # do something

são de fato avaliados como

if bool(value):
    # do something

if not bool(value):
    # do something

Noneé um "falsey", significando que, se convertido em um booleano, ele retornará Falsee, se aplicado, o notoperador retornará True. Observe, no entanto, que não é uma propriedade exclusiva None. Além de Falsesi mesma, a propriedade é compartilhada por listas vazias, tuplas, conjuntos, dictos, seqüências de caracteres, além de 0 e todos os objetos de classes que implementam o __bool__()método mágico para retornar False.

>>> bool(None)
False
>>> not None
True

>>> bool([])
False
>>> not []
True

>>> class MyFalsey(object):
...     def __bool__(self):
...         return False
>>> f = MyFalsey()
>>> bool(f)
False
>>> not f
True

Portanto, ao testar variáveis ​​da seguinte maneira, fique atento ao que você está incluindo ou excluindo do teste:

def some_function(value=None):
    if not value:
        value = init_value()

Acima, você quis chamar init_value()quando o valor está definido especificamente para None, ou você quis dizer que um valor definido como 0, ou a sequência vazia ou uma lista vazia também deveria acionar a inicialização. Como eu disse, fique atento. Como geralmente é o caso explícito em Python, é melhor que implícito .

None na prática

None usado como um valor de sinal

Nonetem um status especial em Python. É um valor de linha de base favorito, porque muitos algoritmos o tratam como um valor excepcional. Em tais cenários, ele pode ser usado como um sinalizador para sinalizar que uma condição requer algum tratamento especial (como a configuração de um valor padrão).

Você pode atribuir Noneaos argumentos de palavra-chave de uma função e testá-la explicitamente.

def my_function(value, param=None):
    if param is None:
        # do something outrageous!

Você pode retorná-lo como padrão ao tentar acessar o atributo de um objeto e testá-lo explicitamente antes de fazer algo especial.

value = getattr(some_obj, 'some_attribute', None)
if value is None:
    # do something spectacular!

Por padrão, o get()método de um dicionário retorna Noneao tentar acessar uma chave inexistente:

>>> some_dict = {}
>>> value = some_dict.get('foo')
>>> value is None
True

Se você tentar acessá-lo usando a notação subscrita, um KeyErrorserá gerado

>>> value = some_dict['foo']
KeyError: 'foo'

Da mesma forma, se você tentar exibir um item não existente

>>> value = some_dict.pop('foo')
KeyError: 'foo'

que você pode suprimir com um valor padrão que geralmente é definido como None

value = some_dict.pop('foo', None)
if value is None:
    # booom!

None usado como sinalizador e valor válido

Os usos descritos acima de Noneaplicar quando não é considerado um valor válido, mas mais como um sinal para fazer algo especial. No entanto, há situações em que às vezes é importante saber de onde Noneveio, porque, embora seja usado como sinal, também pode fazer parte dos dados.

Quando você consulta um objeto em busca de seu atributo, getattr(some_obj, 'attribute_name', None)retornando None, não informa se o atributo que você estava tentando acessar foi definido Noneou se estava totalmente ausente do objeto. A mesma situação ao acessar uma chave de um dicionário como some_dict.get('some_key'), você não sabe se some_dict['some_key']está faltando ou se está apenas definido como None. Se você precisar dessas informações, a maneira usual de lidar com isso é tentar acessar diretamente o atributo ou a chave de dentro de uma try/exceptconstrução:

try:
    # equivalent to getattr() without specifying a default
    # value = getattr(some_obj, 'some_attribute')
    value = some_obj.some_attribute
    # now you handle `None` the data here
    if value is None:
        # do something here because the attribute was set to None
except AttributeError:
    # we're now hanling the exceptional situation from here.
    # We could assign None as a default value if required.
    value = None 
    # In addition, since we now know that some_obj doesn't have the
    # attribute 'some_attribute' we could do something about that.
    log_something(some_obj)

Da mesma forma com dict:

try:
    value = some_dict['some_key']
    if value is None:
        # do something here because 'some_key' is set to None
except KeyError:
    # set a default 
    value = None
    # and do something because 'some_key' was missing
    # from the dict.
    log_something(some_dict)

Os dois exemplos acima mostram como lidar com casos de objetos e dicionários, e as funções? A mesma coisa, mas usamos o argumento de palavra-chave double asteriscos para esse fim:

def my_function(**kwargs):
    try:
        value = kwargs['some_key'] 
        if value is None:
            # do something because 'some_key' is explicitly 
            # set to None
    except KeyError:
        # we assign the default
        value = None
        # and since it's not coming from the caller.
        log_something('did not receive "some_key"')

None usado apenas como um valor válido

Se você achar que seu código está repleto de try/exceptpadrões acima, simplesmente para diferenciar Nonesinalizadores e Nonedados, basta usar outro valor de teste. Há um padrão em que um valor que fica fora do conjunto de valores válidos é inserido como parte dos dados em uma estrutura de dados e é usado para controlar e testar condições especiais (por exemplo, limites, estado, etc.). Esse valor é chamado de sentinela e pode ser usado da maneira que Noneé usado como sinal. É trivial criar um sentinela em Python.

undefined = object()

O undefinedobjeto acima é único e não faz muito de nada que possa interessar a um programa; portanto, é um excelente substituto para Nonecomo sinalizador. Algumas advertências se aplicam, mais sobre isso após o código.

Com função

def my_function(value, param1=undefined, param2=undefined):
    if param1 is undefined:
        # we know nothing was passed to it, not even None
        log_something('param1 was missing')
        param1 = None


    if param2 is undefined:
        # we got nothing here either
        log_something('param2 was missing')
        param2 = None

Com ditado

value = some_dict.get('some_key', undefined)
if value is None:
    log_something("'some_key' was set to None")

if value is undefined:
    # we know that the dict didn't have 'some_key'
    log_something("'some_key' was not set at all")
    value = None

Com um objeto

value = getattr(obj, 'some_attribute', undefined) 
if value is None:
    log_something("'obj.some_attribute' was set to None")
if value is undefined:
    # we know that there's no obj.some_attribute
    log_something("no 'some_attribute' set on obj")
    value = None

Como mencionei anteriormente, as sentinelas personalizadas vêm com algumas ressalvas. Primeiro, não são palavras-chave None, portanto, o python não as protege. Você pode substituir os itens undefinedacima a qualquer momento, em qualquer lugar do módulo definido, portanto, tenha cuidado com a exposição e uso deles. Em seguida, a instância retornada por object()não é um singleton, se você fizer essa chamada 10 vezes, obterá 10 objetos diferentes. Finalmente, o uso de um sentinela é altamente idiossincrático. Um sentinela é específico da biblioteca em que é usado e, portanto, seu escopo geralmente deve ser limitado aos internos da biblioteca. Não deve "vazar". O código externo só deve ficar ciente disso, se seu objetivo é estender ou suplementar a API da biblioteca.

Michael Ekoka
fonte
Que tal: Nada == coisa?
precisa saber é o seguinte
@hkBst Acho que sua pergunta é sobre como o python avalia a igualdade. Ter um olhar para este stackoverflow.com/questions/3588776/...
Michael Ekoka
Ah, então IIUC que normalmente ainda vai acabar chamando coisa .__ eq__? Nesse caso, retiro minha sugestão.
HkBst 02/11/19
@MichaelEkoka, você pode compartilhar a fonte dessas informações impressionantes e úteis.
Anidhya Bhatnagar
Prática padrão. Você pode encontrar algumas dicas sobre isso no tutorial em Python , mas ler o código-fonte de projetos populares é o meu conselho número um para mergulhar rapidamente no Python idiomático .
Michael Ekoka
67

Não é chamado nulo como em outros idiomas, mas None. Sempre há apenas uma instância desse objeto, portanto, você pode verificar a equivalência com x is None(comparação de identidade) em vez de x == None, se desejar.

AndiDog
fonte
25
Vou encontrar uma maneira de quebrar o Python re-instanciando None. Então todas aquelas pessoas inteligentes que compararam NoneTypetriunfarão!
Zenexer
28

No Python, para representar a ausência de um valor, você pode usar o valor Nenhum ( types.NoneType.None ) para objetos e "" (ou len () == 0 ) para seqüências de caracteres. Portanto:

if yourObject is None:  # if yourObject == None:
    ...

if yourString == "":  # if yourString.len() == 0:
    ...

Com relação à diferença entre "==" e "is", o teste da identidade do objeto usando "==" deve ser suficiente. No entanto, como a operação "is" é definida como a operação de identidade do objeto, provavelmente é mais correto usá-la, em vez de "==". Não tenho certeza se existe mesmo uma diferença de velocidade.

De qualquer forma, você pode dar uma olhada em:

Paolo Rovelli
fonte
8
Tanto quanto eu sei, (0 == false) retorna true EM CADA linguagem de programação. Isso ocorre porque false é codificado como 0 e "true" como tudo que NÃO é 0. No entanto, não se esqueça de que o operador "is" não é o mesmo do "==". Essa é mais ou menos a mesma diferença entre "==" e "igual" em Java. O operador "is", na verdade, verifica se DOIS OBJETOS são iguais (a mesma instância e NÃO o mesmo conteúdo)!
Paolo Rovelli
12
Paolo, FYI, (0 == false) não retorna true em todas as linguagens de programação. Um exemplo de contador rápido seria Scala, em que (0 == false) retorna false, e tenho certeza de que Scala não é a única linguagem de programação que retorna false ao comparar um número com um booleano.
22430 Rob Wilton
2
OK, entendi! Então, digamos na maioria das linguagens de programação.
Paolo Rovelli 28/08
3
Em JavaScript, a razão 0 == falseretorna trueé porque o double-iguala operador faz Tipo de coerção. Com o operador triple-equal, no entanto, 0 === falseretorna false, porque 'number' e 'boolean' são tipos diferentes.
Jkdev 18/05
1
@PaoloRovelli, em Lua, Ruby e Clojure, 0 é tratado como trueem condicionais. Em Rust and Go, 0e false diferentes tipos que não podem ser comparados para igualdade.
scooter-dangle
0

Nulo é um tipo de objeto especial como:

>>>type(None)
<class 'NoneType'>

Você pode verificar se um objeto está na classe 'NoneType':

>>>variable = None
>>>variable is None
True

Mais informações estão disponíveis no Python Docs


fonte
-1

Por teste de valor de Verdade , 'None' testa diretamente como FALSE, portanto a expressão mais simples será suficiente:

if not foo:
artejera
fonte
3
Não, não vai. Essa expressão retornará Truepara qualquer valor falso, não apenas None.
insert_name_here
Verdadeiro, e o simples "se não for foo:" não responderia corretamente à pergunta original, como afirmado. No entanto, o python é digitado dinamicamente e convida a reduzir protocolos de sintaxe, portanto, para mim parece válido considerar construções mais simples e similares.
Artejera # 6/17