2013-11-01 1 views
0

У меня есть метод, который устанавливает переменную name, но не существует global name в первой строке, она использует локальную переменную name, поэтому она никогда не изменяет глобальную переменную name. Есть ли способ, чтобы украсить set_name заставить его использовать глобальные name?Изменить область локальной переменной декораторами?

name = "John" 

def set_name(): 
    name = "Sara" 

def print_name(): 
    global name 
    print(name) 

def decorator(func): 
    def wrapper(*args, **kwargs): 
     ## Problem: 
     # Force set_name to use global 'name' 
     func(*args, **kwargs) 

    return wrapper 

print_name() 
#Output: John 

decorator(set_name)() 

print_name() 
# Prints John, but I want to prints Sara 
+4

Может быть, есть какое-то глубокая магия Python, чтобы сделать это, но короткий ответ - нет. Декораторы не меняют функцию, которую они обертывают. –

+1

Я не думаю, что вы можете это сделать ... tbh Мне нелегко видеть, почему вы хотели бы это сделать –

+0

Вы, кажется, определяете класс с методами 'set_name' и' print_name', фактически не объявляя класс. – chepner

ответ

2

Нет, если декоратор не принимает код функции (в байтах-код из объекта коды функции, либо исходный код, используя inspect), изменяет его, создает новый объект кода из измененного кода и заменяет код функции с, что , Это, конечно, крайне ненадежная, хакерская, специфичная для реализации и глубокая черная магия. Просто добавьте global name (или вообще устраните глобальную переменную).

2

Короткий ответ: нет.

Немного расширенный ответ: нет, не в переносном режиме. Технически, вы можете играть с байткодом CPython, но

  • , что не будет работать на любом другом переводчике,
  • никто не сможет понять, что код,
  • головная боль не будет стоит ,
0
name = "John" #global name 

и имя внутри set_name():

name = "Sara" #local name 

Чтобы использовать глобальное имя внутри функции set_name() сделать так:

def set_name(): 
    global name 
    name = "Sara" 
+0

Спасибо, но я имею в виду украшение. – Farhadix

0

Определить класс, который оборачивает name:

class Person(object): 
    def __init__(self): 
     self.name = "John" 

    def set_name(self): 
     self.name = "Sara" 

    def print_name(self): 
     print(name) 

p = Person() 
p.print_name() # Prints John 
p.set_name()  # Changes name to Sara 
p.print_name() # Prints Sara 

Класс, который жестко кодирует его значения атрибутов, как это, конечно, немного глупо, но это демонстрирует цель класса: инкапсулировать данные (name) и функции (set_name, print_name), которые работают на нем.

0

Не уверен, почему вы пытаетесь украсить сеттера.

Вы можете сделать что-то подобное, но я бы не рекомендовал его в качестве обычного стиля кодирования:

name = "John" 

def print_name(): 
    print name 

def decorator(func, tmp_name): 
    def wrapper(*args, **kwargs): 
     global name 
     old_name = name 
     name = tmp_name 
     func(*args, **kwargs) 
     name = old_name 
    return wrapper 

print_name() 
decorator(print_name, 'Sarah')() 
print_name() 

Выход:

John 
Sarah 
John