Как получить доступ к методам и атрибутам в классе производных свойств в Python

Это не имеет никакого отношения к циклам.

Это поведение срабатывает, потому что вы используете лямбда-выражение () => variable * 2, где внешняя область variable фактически не определена во внутренней области лямбда.

Лямбда-выражения (в C # 3 +, а также анонимные методы в C # 2) по-прежнему создают реальные методы. Передача переменных этим методам связана с некоторыми дилеммами (передать по значению? Pass по ссылке? C # идет по ссылке - но это открывает еще одну проблему, когда ссылка может пережить реальную переменную). Что C # для решения всех этих дилемм заключается в создании нового вспомогательного класса («замыкание») с полями, соответствующими локальным переменным, используемым в лямбда-выражениях, и методам, соответствующим фактическим лямбда-методам. Любые изменения в variable в вашем коде фактически преобразуются для изменения в этом ClosureClass.variable

. Таким образом, ваш цикл while обновляет ClosureClass.variable до тех пор, пока он не достигнет 10, тогда вы для циклов выполняете действия, которые все работают на одном и том же ClosureClass.variable.

Чтобы получить ожидаемый результат, вам необходимо создать разделение между переменной цикла и переменной, которая закрывается. Вы можете сделать это, введя другую переменную, то есть:

List<Func<int>> actions = new List<Func<int>>();
int variable = 0;
while (variable < 5)
{
    var t = variable; // now t will be closured (i.e. replaced by a field in the new class)
    actions.Add(() => t * 2);
    ++variable; // changing variable won't affect the closured variable t
}
foreach (var act in actions)
{
    Console.WriteLine(act.Invoke());
}

Вы также можете переместить замыкание на другой метод для создания этого разделения:

List<Func<int>> actions = new List<Func<int>>();

int variable = 0;
while (variable < 5)
{
    actions.Add(Mult(variable));
    ++variable;
}

foreach (var act in actions)
{
    Console.WriteLine(act.Invoke());
}

Вы можете реализовать Mult как лямбда-выражение (неявное замыкание)

static Func<int> Mult(int i)
{
    return () => i * 2;
}

или с фактическим вспомогательным классом:

public class Helper
{
    public int _i;
    public Helper(int i)
    {
        _i = i;
    }
    public int Method()
    {
        return _i * 2;
    }
}

static Func<int> Mult(int i)
{
    Helper help = new Helper(i);
    return help.Method;
}

В любом случае «Closures» не являются концепцией, связанной с циклами, но скорее, к анонимным методам / лямбда-выражениям используют локальные переменные с областью - хотя некоторые неосторожное использование циклов демонстрируют закрытие ловушек.

0
задан Dangraf 16 January 2019 в 20:14
поделиться

2 ответа

get_membervalues не определено внутри myclass, поэтому a не будет иметь к нему доступа.

Он определен внутри myproperty, поэтому следующий логический вывод - попытаться добраться до объекта myproperty, связанного с a.data. Поскольку Python хранит функции в myclass в myclass.__dict__, мы можем найти объект свойства следующим образом:

a.__class__.__dict__['data']

И затем вызвать функцию оттуда:

a.__class__.__dict__['data'].get_membervalues()
>>> {'name': 'data', 'cls_name': 'AnotherClass', 'tooltip': 'help'}
0
ответ дан Primusa 16 January 2019 в 20:14
поделиться

Как получить доступ к методу "get_memvervalues" или атрибутам _name, _tooltip и т. д.?

Из класса (myclass):

myclass.__dict__['data']
[1115 ] Из экземпляра класса (a):

type(a).__dict__['data']

В обоих случаях data является именем атрибута.

Например:

a = myclass()
desc = type(a).__dict__['data']

print(desc.get_membervalues())    # {
                                  #     'name': 'data', 
                                  #     'cls_name': 'AnotherClass', 
                                  #     'tooltip': 'help'
                                  # }

print(desc._tooltip)              # help

print(vars(desc))                 # {
                                  #     '_name': 'data',
                                  #     '_value': 4,
                                  #     '_cls_name': 'AnotherClass', 
                                  #     '_datatype': <class 'int'>, 
                                  #     '_tooltip': 'help', 
                                  #     '_kwargs': {}
                                  # }

Но, на первый взгляд, есть проблема с вашей реализацией:

a = myclass()
b = myclass()

print("Before:")        # Before:
print("a:", a.data)     # a: 4
print("b:", b.data)     # b: 4

a.data = 10

print("After:")         # After:
print("a:", a.data)     # a: 10
print("b:", b.data)     # b: 10   (!!!)

Если это имеет смысл для вас, тогда вы можете прекратить чтение и вы используете дескриптор метода нетрадиционным способом.

Несмотря на наличие двух экземпляров класса, существует только один экземпляр дескриптора:

type(a).__dict__['data'] is type(b).__dict__['data']

(что должно быть очевидно как type(a) is type(b)).

Чтобы поддержать дескриптор, «действующий по-другому», первый аргумент (вы называете его instance в __set__, но он также передается в __get__) является ссылкой на экземпляр класса - это то, что [1112 ] будет внутри традиционного метода.

Обычно вы хотите использовать это как-то.

0
ответ дан jedwards 16 January 2019 в 20:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: