2009-04-23 27 views
7

compact() và extract() là các hàm trong PHP mà tôi thấy rất tiện dụng. compact() lấy danh sách các tên trong bảng biểu tượng và tạo ra một hashtable chỉ với các giá trị của chúng. chiết xuất ngược lại. ví dụ:Python tương đương với PHP() và trích xuất()

$foo = 'what'; 
$bar = 'ever'; 
$a = compact('foo', 'bar'); 
$a['foo'] 
# what 
$a['baz'] = 'another' 
extract(a) 
$baz 
# another 

Có cách nào để thực hiện tương tự trong Python không? Tôi đã xem xét tất cả các xung quanh và gần nhất tôi đã đến là this thread, mà dường như cau mày trên đó.

Tôi biết về người dân địa phương(), globals() và vars(), nhưng làm cách nào tôi có thể chọn thủ công chỉ một tập con các giá trị của họ?

Python có cái gì đó tốt hơn để làm giảm bớt nhu cầu cho điều này không?

+4

Ok, tôi nghĩ tôi thấy điều gì khiến tôi khó hiểu. Có vẻ như dòng 3 của bạn phải là "$ a = nhỏ gọn ('foo', 'bar');" thay thế. – pantsgolem

+0

oops, cảm ơn. Tôi vừa sửa nó. – Turadg

+0

Tôi có thể hỏi tại sao bạn thấy chúng tiện dụng không? Tôi không thấy những gì họ tốt cho rằng không thể được thực hiện sạch sẽ hơn bằng cách sử dụng hashtables. –

Trả lời

10

Đó là không phải là rất Pythonic, nhưng nếu bạn thực sự phải:

import inspect 

def compact(*names): 
    caller = inspect.stack()[1][0] # caller of compact() 
    vars = {} 
    for n in names: 
     if n in caller.f_locals: 
      vars[n] = caller.f_locals[n] 
     elif n in caller.f_globals: 
      vars[n] = caller.f_globals[n] 
    return vars 

def extract(vars): 
    caller = inspect.stack()[1][0] # caller of extract() 
    for n, v in vars.items(): 
     caller.f_locals[n] = v # NEVER DO THIS - not guaranteed to work 

Tôi đã sử dụng những triển khai khá một chút, và họ làm việc, nhưng về mặt kỹ thuật sửa đổi f_locals không được hỗ trợ.

Nghiêm túc, nếu bạn thực sự cảm thấy bạn có nhu cầu sử dụng các chức năng này, có thể bạn đang làm điều gì sai. Dường như nó chạy trên Python's philosophy trên ít nhất ba lần: "rõ ràng là tốt hơn ngầm", "đơn giản hơn là phức tạp", "nếu việc triển khai khó giải thích, đó là một ý tưởng tồi", có thể nhiều hơn (và thực sự, nếu bạn có đủ kinh nghiệm trong Python bạn biết rằng những thứ như thế này không được thực hiện). Tôi có thể thấy nó hữu ích cho một trình gỡ rối hoặc phân tích sau giết mổ, hoặc có lẽ đối với một số loại khung hình rất chung chung thường xuyên cần tạo biến có tên và giá trị được chọn động, nhưng đó là một đoạn.

Nếu bạn định sử dụng các chức năng này, ít nhất bạn nên giữ các biến số extract ed chứa trong phạm vi nhỏ. Bọc chúng vào các chức năng mà bạn có thể coi là "hộp đen". Lý do chính extract là xấu là nó đặt các biến trong bảng biểu tượng của bạn theo cách không rõ ràng từ việc kiểm tra mã. Nếu bạn giữ các hiệu ứng của các biến được bản địa hóa thành một hàm rất nhỏ, và giải thích những gì bạn đang làm với mã và nhận xét rõ ràng, nó không phải là vấn đề lớn.

2

tôi đoán tương đương với extract($x)globals().update(x), như đối với compact() đó là một tập hợp con của vars()

>>> foo, bar, baz = 1, 2, 3 
# extract 
>>> globals().update({"foo": 4, "qux": 5}) 
>>> foo 
4 
>>> qux 
5 
# compact 
>>> d = dict((k, v) for k, v in vars().iteritems() if k in ["foo", "bar"]) 
>>> d 
{'bar': 2, 'foo': 1} 
9

Tôi sợ không có tương đương trong Python. Chừng mực nào đó, bạn có thể mô phỏng hiệu ứng của họ sử dụng (và qua) locals:

>>> def compact(locals, *keys): 
...  return dict((k, locals[k]) for k in keys) 
... 
>>> a = 10 
>>> b = 2 
>>> compact(locals(), 'a', 'b') 
{'a': 10, 'b': 2} 

>>> def extract(locals, d): 
...  for k, v in d.items(): 
...   locals[k] = v 
... 
>>> extract(locals(), {'a': 'foo', 'b': 'bar'} 
>>> a 
'foo' 
>>> b 
'bar' 

Tuy nhiên, tôi không nghĩ rằng các chức năng này là "rất tiện dụng". Các biến toàn cầu/cục bộ động là ác và dễ bị lỗi - những người PHP đã học được rằng khi họ không khuyến khích register_globals. Theo kinh nghiệm của tôi, vài lập trình viên PHP có kinh nghiệm hoặc các khung chính sử dụng compact() hoặc extract().

Trong Python, explicit is better than implicit:

a = 1 
b = 2 
# compact 
c = dict(a=a, b=b) 

# extract 
a, b = d['a'], d['b'] 
+0

Tôi là tất cả cho rõ ràng, nhưng tại sao nó phải được dự phòng? điều này sẽ không dễ bị lỗi hơn? c = nhỏ gọn (a, b) – Turadg

+6

Không sửa đổi người dân địa phương()! http://docs.python.org/library/functions.html#locals –

6

Có giá trị chỉ ra rằng extract() (và đến một mức độ thấp hơn, compact()) là một trong những hầu hết các tính năng "độc ác" của PHP (cùng với register_globalseval), và nên tránh?

extract khiến việc xác định vị trí biến được xác định là khó khăn hơn nhiều. Khi khó theo dõi một biến trở lại nơi nó được xác định, khó kiểm tra các vấn đề bảo mật phổ biến như sử dụng các biến chưa được khởi tạo hoặc các biến chưa được lọc bắt nguồn từ đầu vào của người dùng.

compact không phải là xấu, nhưng nếu được sử dụng kém vẫn có thể làm cho nó khó khăn hơn nó sẽ được để xem nơi một thành viên mảng được thiết lập từ một biến.

Tương đương với extract() bằng nhiều ngôn ngữ khác là từ khóa with. Python hiện có từ khóa with, mặc dù nó hoạt động hơi khác một chút, làm cho nó không giống như extract(). Tuy nhiên, trong các ngôn ngữ khác như Javascript, từ khóa withalso has a poor reputation.

Tôi nghĩ rằng lời khuyên tốt nhất là suy nghĩ khác - thay vì cố gắng mô phỏng một tính năng xấu của PHP, hãy nghĩ cách khác để làm những gì bạn muốn làm với mã súc tích và dễ đọc.

+1

Xin lưu ý rằng câu lệnh 'with' trong Python có ngữ nghĩa hoàn toàn khác với trong JavaScript và không thay đổi bất kỳ "phạm vi biến" nào. Ngoài ra nó là một tính năng khá mới và chắc chắn không có danh tiếng nghèo. Tuy nhiên, bạn đúng với JavaScript- "với". –

+0

Cảm ơn Ferdinand, tôi đã chỉnh sửa câu trả lời một chút – thomasrutter

+0

Tôi đã chỉnh sửa câu trả lời cho đến thời điểm không còn ý nghĩa bởi vì nó không phù hợp với một nhận xét, nhưng tất cả đều quan trọng. Tôi đã không quay trở lại sau đó bởi vì nó đã được chuyển đổi thành một bình luận. Tôi đã xóa nó bởi vì tôi cảm thấy nó không trả lời câu hỏi, bởi vì, vì nó được viết trong câu đầu tiên của nhận xét của bạn, bạn chỉ đang chỉ ra điều gì đó. – Ryan

3

chức năng của PHP nhỏ gọn trong Python (chỉ hoạt động với 2,6; không được bảo đảm để làm việc với các phiên bản trước đó của Python):

import inspect 
def compact(*args): 
    return dict([(i, inspect.currentframe().f_back.f_locals.get(i, None)) 
        for i in args]) 

Tôi đã viết nhiều hơn về vấn đề này: Python can be just as ugly as PHP.

1

Bạn thể làm điều này (mặc dù tôi sẽ đề nghị chỉ ít ...) với locals() chức năng, mà trả về một thể cập nhật dict. Ví dụ:

$ python 
Python 2.7.12 (default, Jul 1 2016, 15:12:24) 
>>> locals().update({'derek':'anderson'}) 
>>> derek 
'anderson' 
>>> 

Vì vậy locals() sẽ là "nhỏ gọn tất cả" và locals().update() sẽ extract.

Best of luck!

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