Giá trị Không là gì?


130

Tôi đã nghiên cứu Python và tôi đã đọc một chương mô tả Nonegiá trị, nhưng tiếc là cuốn sách này không rõ ràng ở một số điểm. Tôi nghĩ rằng tôi sẽ tìm thấy câu trả lời cho câu hỏi của mình, nếu tôi chia sẻ nó ở đó.

Tôi muốn biết Nonegiá trị gì và bạn sử dụng nó để làm gì?

Ngoài ra, tôi không nhận được phần này của cuốn sách:

Gán một giá trị Nonecho một biến là một cách để đặt lại nó về trạng thái trống ban đầu.

Điều đó nghĩa là gì?

Các câu trả lời rất hay, mặc dù tôi không hiểu hầu hết các câu trả lời do kiến ​​thức thấp về thế giới máy tính (tôi chưa học về các lớp học, đồ vật, v.v.). Câu văn này có nghĩa là gì?

Gán một giá trị Nonecho một biến là một cách để đặt lại nó về trạng thái trống ban đầu.

Sau cùng:

Cuối cùng, tôi đã có câu trả lời của mình từ việc tìm kiếm các câu trả lời khác nhau. Tôi phải đánh giá cao tất cả những người đã dành thời gian của họ để giúp tôi (đặc biệt là Martijn Pieters và DSM), và tôi ước rằng tôi có thể chọn tất cả các câu trả lời là tốt nhất, nhưng lựa chọn chỉ giới hạn ở một. Tất cả các câu trả lời là tuyệt vời.


39
Cuốn sách đó không quá hữu ích; Nonekhông phải là trạng thái trống mặc định cho các biến.
Martijn Pieters

Ngoài đỉnh đầu của tôi, php là ngôn ngữ duy nhất có giá trị null tương đương với trạng thái trống mặc định cho một biến. Bây giờ tôi đang tự hỏi những ngôn ngữ khác làm điều đó.
kojiro

@kojiro perl, mặc dù cả hai nhà khai thác bình đẳng đều không hài lòng về việc so sánh với undef. cũng được cho là javascript, mặc dù nó có cả nullundefined.
Eevee

Giá trị mặc định của biến @kojiro javascript là undefined, nếu không được khởi tạo.
thefourtheye

Đúng, khác với null, một điểm tôi không thể thực hiện với @MartijnPieters trong câu trả lời của mình.
kojiro

Câu trả lời:


99

Câu trả lời của Martijn giải thích những gì Nonecó trong Python và nói chính xác rằng cuốn sách đang gây hiểu nhầm. Vì các lập trình viên Python như một quy luật sẽ không bao giờ nói

Gán một giá trị Nonecho một biến là một cách để đặt lại nó về trạng thái trống ban đầu.

thật khó để giải thích ý nghĩa của Briggs theo cách có ý nghĩa và giải thích tại sao không ai ở đây có vẻ hài lòng với nó. Một sự tương tự có thể giúp:

Trong Python, tên biến giống như nhãn dán đặt trên các đối tượng. Mỗi nhãn dán có một tên duy nhất được viết trên đó và nó chỉ có thể được đặt trên một đối tượng tại một thời điểm, nhưng bạn có thể đặt nhiều nhãn dán trên cùng một đối tượng, nếu bạn muốn. Khi bạn viết

F = "fork"

bạn đặt nhãn dán "F" lên một đối tượng chuỗi "fork". Nếu bạn sau đó viết

F = None

bạn di chuyển nhãn dán vào Noneđối tượng.

Điều mà Briggs yêu cầu bạn tưởng tượng là bạn đã không viết nhãn dán "F", đã một Fnhãn dán trên đó Nonevà tất cả những gì bạn đã làm là chuyển nó, từ Nonesang "fork". Vì vậy, khi bạn nhập F = None, bạn sẽ "đặt lại [ting] nó về trạng thái ban đầu, trống rỗng", nếu chúng tôi quyết định coi Nonelà có nghĩa empty state.

Tôi có thể thấy những gì anh ấy đang nhận được, nhưng đó là một cách tồi để xem xét nó. Nếu bạn khởi động Python và gõ print(F), bạn sẽ thấy

>>> print(F)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'F' is not defined

và điều đó NameErrorcó nghĩa là Python không nhận ra tên F, vì không có nhãn dán nào như vậy . Nếu Briggs đã đúng và F = Noneđặt lại Fvề trạng thái ban đầu, thì nó sẽ ở đó ngay bây giờ và chúng ta sẽ thấy

>>> print(F)
None

giống như chúng ta làm sau khi chúng ta gõ F = Nonevà dán nhãn dán vào None.


Vì vậy, đó là tất cả những gì đang diễn ra. Trên thực tế, Python đi kèm với một số nhãn đã gắn liền với đối tượng (built-in tên), nhưng những người khác bạn phải viết bản thân với những đường nét như F = "fork"A = 2c17 = 3.14, và sau đó bạn có thể dính chúng trên các đối tượng khác sau này (như F = 10hay F = None, nó là tất cả cùng .)

Briggs đang giả vờ rằng tất cả các nhãn dán có thể bạn có thể muốn viết đã bị mắc kẹt vào Noneđối tượng.


1
xin lỗi nhưng ý của Briggs là gì? bạn đang đề cập đến tác giả của cuốn sách này phải không? bởi vì tên anh ta là Jason R. Briggs.
The_Diver

@The_Diver: vâng, đó là anh ấy.
DSM

Tôi có thể tìm thêm thông tin về tên dựng sẵn của Python ở đâu? Cảm ơn.
The_Diver

3
Đây là một lời giải thích tuyệt vời cho một người không lập trình. Cảm ơn rât nhiều!
Christina

67

Nonechỉ là một giá trị thường được sử dụng để biểu thị 'trống rỗng' hoặc 'không có giá trị ở đây'. Nó là một đối tượng tín hiệu ; nó chỉ có ý nghĩa bởi vì tài liệu Python nói rằng nó có ý nghĩa đó.

Chỉ có một bản sao của đối tượng đó trong phiên phiên dịch Python đã cho.

Ví dụ, nếu bạn viết một hàm và hàm đó không sử dụng returncâu lệnh rõ ràng , Nonesẽ được trả về. Bằng cách đó, lập trình với các chức năng được đơn giản hóa hơn nhiều; một hàm luôn trả về một cái gì đó , ngay cả khi nó chỉ là một Noneđối tượng.

Bạn có thể kiểm tra nó một cách rõ ràng:

if foo is None:
    # foo is set to None

if bar is not None:
    # bar is set to something *other* than None

Một cách sử dụng khác là cung cấp các tham số tùy chọn cho các chức năng mặc định 'trống':

def spam(foo=None):
    if foo is not None:
        # foo was specified, do something clever!

Hàm spam()này có một đối số tùy chọn; nếu bạn gọi spam()mà không chỉ định nó, giá trị mặc định Noneđược trao cho nó, giúp dễ dàng phát hiện xem hàm có được gọi với một đối số hay không.

Các ngôn ngữ khác có khái niệm tương tự. SQL có NULL; JavaScript có undefined null , v.v.

Lưu ý rằng trong Python, các biến tồn tại nhờ vào việc được sử dụng. Bạn không cần phải khai báo một biến trước, vì vậy không có biến nào thực sự trống trong Python. Đặt một biến thành Nonesau đó không giống như đặt nó thành một giá trị trống mặc định; Nonecũng là một giá trị, mặc dù thường được sử dụng để báo hiệu sự trống rỗng. Cuốn sách bạn đang đọc là sai lệch về điểm đó.


1
Tôi nghĩ rằng ngữ nghĩa của sự trống rỗng khác với những điều không xác định . Vì vậy, tôi không chắc các đối tác JavaScript và SQL đang làm rõ - họ có thể nhầm lẫn vấn đề này. JavaScript có cả undefined null .
kojiro

@kojiro: undefinedlà một đối tượng trong JavaScript và bạn có thể sử dụng đối tượng đó một cách rõ ràng giống như bạn có thể sử dụng Nonetrong Python. Nó là một đối tượng tín hiệu, với nhiều ý nghĩa tương tự.
Martijn Pieters

@kojiro: SQL không phải là ngôn ngữ lập trình, nhưng NULLvẫn là thứ có thể được gán và kiểm tra rõ ràng.
Martijn Pieters

5
@MartijnPieters: SQL ngôn ngữ lập trình, chỉ là mục đích rất cụ thể, khai báo.
danielkza

3
@daniel: Wether SQL đủ điều kiện là ngôn ngữ lập trình đã là một cuộc tranh luận lâu dài ... Xem stackoverflow.com/questions/900055/ cho các góc thú vị.
Martijn Pieters

23

Đây là những gì tài liệu Python đã nói về None:

Giá trị duy nhất của các loại.NoneType. Không có thường được sử dụng để thể hiện sự vắng mặt của một giá trị, vì khi các đối số mặc định không được truyền cho một hàm.

Đã thay đổi trong phiên bản 2.4: Việc chuyển nhượng thành Không có gì là bất hợp pháp và đưa ra một SyntaxError.

Lưu ý Tên Không và gỡ lỗi không thể được gán lại (gán cho chúng, ngay cả khi là tên thuộc tính, nâng SyntaxError), vì vậy chúng có thể được coi là hằng số đúng.

  1. Hãy xác nhận loại Noneđầu tiên

    print type(None)
    print None.__class__

    Đầu ra

    <type 'NoneType'>
    <type 'NoneType'>

Về cơ bản, NoneTypelà một kiểu dữ liệu giống như int, floatv.v. Bạn có thể kiểm tra danh sách các kiểu mặc định có sẵn trong Python trong 8.15. loại - Tên cho các loại tích hợp .

  1. Và, Nonelà một ví dụ của NoneTypelớp. Vì vậy, chúng tôi có thể muốn tạo ra các trường hợp của Nonechính chúng ta. Hãy thử xem

    print types.IntType()
    print types.NoneType()

    Đầu ra

    0
    TypeError: cannot create 'NoneType' instances

Vì vậy, rõ ràng, không thể tạo ra các NoneTypetrường hợp. Chúng tôi không phải lo lắng về tính độc đáo của giá trị None.

  1. Hãy kiểm tra xem chúng tôi đã triển khai Nonenội bộ như thế nào .

    print dir(None)

    Đầu ra

    ['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', 
     '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__',
     '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

Ngoại trừ __setattr__, tất cả những thứ khác là thuộc tính chỉ đọc. Vì vậy, không có cách nào chúng ta có thể thay đổi các thuộc tính của None.

  1. Hãy thử và thêm các thuộc tính mới vào None

    setattr(types.NoneType, 'somefield', 'somevalue')
    setattr(None, 'somefield', 'somevalue')
    None.somefield = 'somevalue'

    Đầu ra

    TypeError: can't set attributes of built-in/extension type 'NoneType'
    AttributeError: 'NoneType' object has no attribute 'somefield'
    AttributeError: 'NoneType' object has no attribute 'somefield'

Các báo cáo nhìn thấy ở trên tạo ra các thông báo lỗi, tương ứng. Điều đó có nghĩa là, chúng ta không thể tạo các thuộc tính động trên một Nonethể hiện.

  1. Hãy để chúng tôi kiểm tra những gì xảy ra khi chúng tôi chỉ định một cái gì đó None. Theo tài liệu, nó nên ném a SyntaxError. Điều đó có nghĩa là, nếu chúng ta gán một cái gì đó cho None, chương trình sẽ hoàn toàn không được thực thi.

    None = 1

    Đầu ra

    SyntaxError: cannot assign to None

Chúng tôi đã thiết lập rằng

  1. None là một ví dụ của NoneType
  2. None không thể có thuộc tính mới
  3. Thuộc tính hiện tại của Nonekhông thể được thay đổi.
  4. Chúng tôi không thể tạo các phiên bản khác của NoneType
  5. Chúng tôi thậm chí không thể thay đổi tham chiếu đến Nonebằng cách gán giá trị cho nó.

Vì vậy, như đã đề cập trong tài liệu, Nonethực sự có thể được coi là một true constant.

Hạnh phúc khi biết None:)


Rất rất thú vị !! người ta nghi ngờ những gì được sử dụng __setattr__cho Không
Grijesh Chauhan

9

Cuốn sách bạn đề cập rõ ràng đang cố gắng đơn giản hóa rất nhiều ý nghĩa của None. Các biến Python không trạng thái trống, ban đầu - Các biến Python bị ràng buộc (chỉ) khi chúng được xác định . Bạn không thể tạo một biến Python mà không cho nó một giá trị.

>>> print(x)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> def test(x):
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: test() takes exactly 1 argument (0 given)
>>> def test():
...   print(x)
... 
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in test
NameError: global name 'x' is not defined

nhưng đôi khi bạn muốn làm cho một hàm có nghĩa là những thứ khác nhau tùy thuộc vào việc một biến được định nghĩa hay không. Bạn có thể tạo một đối số có giá trị mặc định là None:

>>> def test(x=None):
...   if x is None:
...     print('no x here')
...   else:
...     print(x)
... 
>>> test()
no x here
>>> test('x!')
x!

Thực tế là giá trị này là giá trị đặc biệt Nonekhông quan trọng lắm trong trường hợp này. Tôi đã có thể sử dụng bất kỳ giá trị mặc định:

>>> def test(x=-1):
...   if x == -1:
...     print('no x here')
...   else:
...     print(x)
... 
>>> test()
no x here
>>> test('x!')
x!

Sôi nhưng có Nonexung quanh cho chúng ta hai lợi ích:

  1. Chúng ta không phải chọn một giá trị đặc biệt như -1ý nghĩa của nó không rõ ràng và
  2. Chức năng của chúng tôi thực sự có thể cần phải xử lý -1như một đầu vào bình thường.
>>> test(-1)
no x here

Giáo sư!

Vì vậy, cuốn sách hơi sai lệch chủ yếu trong việc sử dụng thiết lập lại từ - gán Nonetên là một tín hiệu cho lập trình viên rằng giá trị đó không được sử dụng hoặc chức năng nên hoạt động theo cách mặc định, nhưng để đặt lại giá trị đến trạng thái ban đầu, không xác định, bạn phải sử dụng deltừ khóa:

>>> x = 3
>>> x
3
>>> del x
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

5

Các câu trả lời khác đã giải thích ý nghĩa của Không có gì đẹp. Tuy nhiên, tôi vẫn muốn ném thêm ánh sáng vào điều này bằng một ví dụ.

Thí dụ:

def extendList(val, list=[]):
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

Bây giờ hãy thử đoán đầu ra của danh sách trên. Vâng, câu trả lời là đáng ngạc nhiên như dưới đây:

list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

Nhưng tại sao?

Nhiều người sẽ nhầm tưởng list1 sẽ bằng [10]list3 bằng với ['a'] , vì nghĩ rằng đối số danh sách sẽ được đặt thành giá trị mặc định của [] mỗi lần extList được gọi.

Tuy nhiên, điều thực sự xảy ra là danh sách mặc định mới chỉ được tạo một lần khi hàm được xác định và danh sách đó sẽ được sử dụng sau đó bất cứ khi nào extList được gọi mà không có đối số danh sách được chỉ định. Điều này là do các biểu thức trong các đối số mặc định được tính khi hàm được xác định, không phải khi nó được gọi .

list1list3 do đó hoạt động trên cùng một danh sách mặc định, trong khi list2 đang hoạt động trên một danh sách riêng mà nó đã tạo (bằng cách chuyển danh sách trống của chính nó làm giá trị cho tham số danh sách).


'Không' vị cứu tinh: (Sửa đổi ví dụ ở trên để tạo hành vi mong muốn)

def extendList(val, list=None):
    if list is None:
       list = []
    list.append(val)
    return list

list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')

print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

Với việc thực hiện sửa đổi này, đầu ra sẽ là:

list1 = [10]
list2 = [123]
list3 = ['a']

Lưu ý - Ví dụ tín dụng cho toptal.com


3

Không có đối tượng đơn lẻ (có nghĩa là chỉ có một Không có), được sử dụng ở nhiều nơi trong ngôn ngữ và thư viện để thể hiện sự vắng mặt của một số giá trị khác.


Ví dụ:
if dlà một từ điển, d.get(k)sẽ trả về d[k]nếu nó tồn tại, nhưng Nonenếu dkhông có khóa k.

Đọc thông tin này từ một blog tuyệt vời: http://python-history.blogspot.in/


3

Tất cả đều là những câu trả lời hay nhưng tôi nghĩ có nhiều điều để giải thích tại sao lại Nonehữu ích.

Hãy tưởng tượng bạn thu thập RSVP cho một đám cưới. Bạn muốn ghi lại xem mỗi người sẽ tham dự. Nếu họ đang tham dự, bạn thiết lập person.attending = True. Nếu họ không tham dự bạn thiết lập person.attending = False. Nếu bạn chưa nhận được bất kỳ RSVP nào person.attending = None. Bằng cách đó bạn có thể phân biệt giữa không có thông tin None- và một câu trả lời tiêu cực.


1

Tôi thích các ví dụ mã (cũng như trái cây), vì vậy hãy để tôi chỉ cho bạn

apple = "apple"
print(apple)
>>> apple
apple = None
print(apple)
>>> None

Không có nghĩa là không có gì, nó không có giá trị.

Không có đánh giá nào là Sai.


8
print(None)in .. None. Nó không , như bạn đề nghị, không in gì cả.
Martijn Pieters

REPL chỉ hiển thị không có gì Nonenếu đó là kết quả của biểu thức cuối cùng. (phần lớn hữu ích cho các hàm không có ý định trả về giá trị.)
Eevee

Rất tiếc, tôi đã sử dụng IDLE và tôi cho rằng nó đã in các biến, rõ ràng là nó sử dụng thay thế. Tôi hiện đang sử dụng SO để hoàn thiện các kỹ năng đọc và hiểu mã python / javascript của riêng mình, vì vậy tôi đang mắc một số lỗi :(
Azeirah

2
IDLE, giống như lời nhắc của trình thông dịch tương tác Python, ẩn rõ ràng Nonenếu đó là kết quả của một biểu thức, chủ yếu là không làm lộn xộn đầu ra.
Martijn Pieters

-5
largest=none
smallest =none 
While True :
          num =raw_input ('enter a number ') 
          if num =="done ": break 
          try :
           inp =int (inp) 
          except:
              Print'Invalid input' 
           if largest is none :
               largest=inp
           elif inp>largest:
                largest =none 
           print 'maximum', largest

          if smallest is none:
               smallest =none
          elif inp<smallest :
               smallest =inp
          print 'minimum', smallest 

print 'maximum, minimum, largest, smallest 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.