2011-09-07 61 views
27

Tôi là một lập trình viên RoR mới với Python. Tôi đang cố gắng tìm cú pháp sẽ cho phép tôi đặt biến thành giá trị cụ thể chỉ khi nó không được gán trước đó. Về cơ bản tôi muốn:Python: Gán Giá trị nếu Không tồn tại

# only if var1 has not been previously assigned

var1 = 4

+6

Trong trường hợp nào bạn sẽ tham chiếu các biến có thể không tồn tại? Bạn có muốn tham chiếu các biến đã được khai báo nhưng chưa được khởi tạo không? – mwcz

Trả lời

18

Đây là một phong cách rất khác nhau của chương trình, nhưng tôi luôn cố gắng để viết lại những điều mà trông giống như

bar = None 
if foo(): 
    bar = "Baz" 

if bar is None: 
    bar = "Quux" 

thành chỉ:

if foo(): 
    bar = "Baz" 
else: 
    bar = "Quux" 

Đó là để nói, tôi cố gắng hết sức để tránh một tình huống mà một số đường dẫn mã xác định các biến nhưng một số khác thì không. Trong mã của tôi, không bao giờ có một con đường gây ra sự mơ hồ của tập các biến được xác định (Thực tế, tôi thường tiến thêm một bước nữa và đảm bảo rằng các loại giống nhau bất kể đường dẫn mã). Nó có thể chỉ là một vấn đề về sở thích cá nhân, nhưng tôi tìm thấy mô hình này, mặc dù một chút ít rõ ràng hơn khi tôi viết nó, dễ hiểu hơn nhiều khi tôi đọc nó.

+37

Điều này thậm chí có thể được rút gọn trong một lớp lót bằng cách sử dụng 'bar =" Baz "nếu foo() khác" Quux "' – MatToufoutu

+0

@grokpot: không nên thay đổi bất kỳ điều gì, cả hai đoạn mã phải được thực hiện hoặc không cho cùng một thứ được trả về bởi 'foo()' – SingleNegationElimination

+0

@grokpot: đọc hai đoạn mã một cách cẩn thận, nó không kiểm tra nếu 'foo()' trả về 'None', nó sẽ kiểm tra nếu' bar' vẫn là 'None'. Nếu bạn có thể cung cấp một định nghĩa 'foo()' sẽ làm cho hai đoạn mã cung cấp cho các bài tập 'bar' khác nhau, tôi sẽ mua cho bạn một chai Scotch ưa thích (hoặc bất kỳ thứ gì bạn thích) – SingleNegationElimination

56

Bạn nên khởi tạo các biến để None và sau đó kiểm tra xem nó:

var1 = None 
if var1 is None: 
    var1 = 4 

Mà có thể được viết trong một dòng như:

var1 = 4 if var1 is None else var1 

hoặc sử dụng lối tắt (nhưng kiểm tra lại Không được khuyến khích)

var1 = var1 or 4 

cách khác nếu bạn sẽ không có bất cứ điều gì được gán cho biến mà tên biến không tồn tại và do đó sử dụng mà sau này sẽ nâng cao NameError, và bạn cũng có thể sử dụng kiến ​​thức đó để làm một cái gì đó giống như

này
try: 
    var1 
except NameError: 
    var1 = 4 

nhưng tôi khuyên bạn nên chống lại điều đó.

+0

Lưu ý rằng nếu bạn muốn gán một giá trị, bạn cần khai báo 'global' /' nonlocal' hoặc sử dụng 'ngoại trừ UnboundLocalError' (và chấp nhận biến sẽ là cục bộ và giá trị toàn cục sẽ bị bỏ qua). – delnan

+0

@delnan nơi trong ví dụ của tôi, tôi sẽ nhận được UnboundLocalError? –

+2

Do việc gán sau này (trong 'except'),' var1' là một biến cục bộ, trừ khi đoạn mã ở mức mô-đun (có nghĩa là, toàn cầu) hoặc có một dòng 'global var1'. Việc truy cập một biến cục bộ chưa được gán sẽ làm tăng 'UnboundLocalError' thay vì' NameError' (được dành riêng cho các tên toàn cầu). – delnan

0

Nếu bạn có nghĩa là một biến ở cấp mô-đun sau đó bạn có thể sử dụng "globals":

if "var1" not in globals(): 
    var1 = 4 

nhưng Python thành ngữ phổ biến là để khởi tạo nó để nói None (giả định rằng nó không phải là một giá trị có thể chấp nhận) và sau đó thử nghiệm với if var1 is not None.

+7

Bằng cách đó là sự điên rồ. Điều này phá vỡ các biến cục bộ, sử dụng 'local()' break trên globals, và tôi không nghĩ rằng nó hoạt động với nonlocals. Để khắc phục điều đó, người ta sẽ phải mô phỏng toàn bộ quy tắc phạm vi hoặc viết mã giả định một trong hai quy tắc đó. – delnan

+2

@delnan: Giới thiệu về địa phương/nonglobal đây là những gì tôi có nghĩa là với "Nếu bạn có nghĩa là một biến ở cấp mô-đun". Về cái ngu ngốc đó "Đó là cách điên rồ" bạn nên nói với OP, không phải tôi ... bằng cách nào đó trong câu trả lời là thực sự nói rằng đây không phải là việc nên làm. – 6502

15
var1 = var1 or 4 

Vấn đề duy nhất có thể là nếu var1 là giá trị falsey, như False hoặc 0 hoặc [], nó sẽ chọn 4 thay thế. Đó có thể là một vấn đề.

+2

Xem [kiểm tra giá trị sự thật] (https://docs.python.org/2/library/stdtypes.html#truth-value-testing) để có danh sách đầy đủ những thứ đánh giá sai, một số có thể gây ngạc nhiên cho một số . – ecerulm

2

Câu trả lời của IfLoop (và nhận xét của MatToufoutu) hoạt động tốt cho các biến độc lập, nhưng tôi muốn cung cấp câu trả lời cho bất kỳ ai đang cố gắng làm điều gì đó tương tự cho các mục riêng lẻ trong danh sách, bộ hoặc từ điển.

Từ điển

existing_dict = {"spam": 1, "eggs": 2} 
existing_dict["foo"] = existing_dict["foo"] if "foo" in existing_dict else 3 

Returns {"spam": 1, "eggs": 2, "foo": 3}

Lists

existing_list = ["spam","eggs"] 
existing_list = existing_list if len(existing_list)==3 else 
       existing_list + ["foo"] 

Returns ["spam", "eggs", "foo"]

Tuples

existing_tuple = ("spam","eggs") 
existing_tuple = existing_tuple if len(existing_tuple)==3 else 
       existing_tuple + ("foo",) 

Returns ("spam", "eggs", "foo")

(Đừng quên dấu phẩy trong ("foo",) để xác định một "duy nhất" tuple.)

Các danh sách và các bộ giải pháp sẽ phức tạp hơn nếu bạn muốn để làm nhiều hơn là chỉ kiểm tra độ dài và nối thêm vào cuối. Tuy nhiên, điều này mang lại một hương vị của những gì bạn có thể làm.

+0

Tất cả các câu trả lời của bạn đều bị hỏng. –

+1

@ SébastienDeprez Bạn đã thực sự chính xác. Cảm ơn bạn đã chỉ ra. Tôi đã thực hiện các chỉnh sửa để giải quyết các vấn đề. –

10

Tôi cũng đến từ Ruby vì vậy tôi yêu cú pháp foo ||= 7.

Đây là điều gần nhất tôi có thể tìm thấy.

foo = foo if 'foo' in vars() else 7 

người mà tôi đã nhìn thấy làm việc này cho một dict:

try: 
    foo['bar'] 
except KeyError: 
    foo['bar'] = 7 

Upadate: Tuy nhiên, tôi vừa tìm thấy viên ngọc này:

foo['bar'] = foo.get('bar', 7) 

Nếu bạn như thế, sau đó cho một biến thông thường bạn có thể làm một cái gì đó như thế này:

vars()['foo'] = vars().get('foo', 7) 
+0

Làm thế nào điều này sẽ làm việc cho các biến ví dụ trong một lớp học? self.foo = ...? – CodeKid

+1

@CodeKid 'self.foo = self .__ dict __. Get ('foo', 7)' –

+1

@CodeKid Hoặc, 'self.foo = getattr (self, 'foo', 7)' – kkurian

Các vấn đề liên quan