Właśnie wpadłem w sytuację, w której nazwy członków klasy Pseudo nie są zmogliwy podczas stosowania setattr lub exec.

In [1]: class T:
   ...:     def __init__(self, **kwargs):
   ...:         self.__x = 1
   ...:         for k, v in kwargs.items():
   ...:             setattr(self, "__%s" % k, v)
   ...:         
In [2]: T(y=2).__dict__
Out[2]: {'_T__x': 1, '__y': 2}

Próbowałem exec("self.__%s = %s" % (k, v)), a także z tym samym wynikiem:

In [1]: class T:
   ...:     def __init__(self, **kwargs):
   ...:         self.__x = 1
   ...:         for k, v in kwargs.items():
   ...:             exec("self.__%s = %s" % (k, v))
   ...:         
In [2]: T(z=3).__dict__
Out[2]: {'_T__x': 1, '__z': 3}

Robiący self.__dict__["_%s__%s" % (self.__class__.__name__, k)] = v byłby działał, ale __dict__ jest readonly atrybutem.

Czy istnieje inny sposób, w jaki mogę dynamicznie stworzyć członkom klas PSUDO -Private (bez twardego kodowania w nazwie zmanglowanie)?


Lepszy sposób na wyrażenie moje pytanie:

Co robi Python "pod kapturem", gdy napotyka podwójnie podkreśla ({x0}}) Czy istnieje magiczna funkcja, która służy do wykonywania zmangingu?

8
chown 16 październik 2011, 07:51

2 odpowiedzi

Adresowanie tego:

Co robi Python "pod maską", kiedy napotyka podwójny Underscore ({x0}}) Atrybut jest ustawiony? Czy istnieje funkcja magiczna używany jest do wykonania zmangielania?

Afaik, jest zasadniczo specjalny w kompilatorze. Więc raz w ByteCode nazwa jest już zniebrana; Interpreter nigdy nie widzi w ogóle nieznanej nazwy i nie miał pojęcia o żadnej specjalnej obsługi potrzebnej. Dlatego odwołuje się do setattr, exec lub patrząc w górę ciąg w __dict__ nie działa; Kompilator widzi wszystkie te jako ciągi i nie wie, że mają coś wspólnego z dostępem do atrybutu, więc przekazuje je przez niezmienione. Interpreter nie zna niczego o nazwisku, więc po prostu używa ich bezpośrednio.

Times, które musiałem to przejść, po prostu ręcznie wykonałem tę samą nazwę, hacky tak, jak to jest. Odkryłem, że przy użyciu tych "prywatnych" nazw jest ogólnie zły pomysł, chyba że jest to przypadek, w którym wiesz, że potrzebujesz ich do zamierzonego celu: aby umożliwić hierarchię spadków klas do wszystkich użyć tej samej nazwy atrybutów, ale mieć kopię na klasę. Pieprzowe nazwy atrybutów z podwójnymi podkreśleniem tylko dlatego, że mają być prywatnymi szczegółami wdrażania, wydaje się powodować bardziej szkody niż korzyści; Podjęłem tylko za pomocą jednego podkreślenia jako podpowiedzi, że kod zewnętrzny nie powinien go dotykać.

4
Ben 17 październik 2011, 05:14

Oto do tej pory hack. Sugestie dotyczące poprawy są mile widziane.

class T(object):

    def __init__(self, **kwds):
        for k, v in kwds.items():
            d = {}
            cls_name = self.__class__.__name__

            eval(compile(
                'class dummy: pass\n'
                'class {0}: __{1} = 0'.format(cls_name, k), '', 'exec'), d)

            d1, d2 = d['dummy'].__dict__, d[cls_name].__dict__
            k = next(k for k in d2 if k not in d1)

            setattr(self, k, v)

>>> t = T(x=1, y=2, z=3)
>>> t._T__x, t._T__y, t._T__z
(1, 2, 3)
2
Eryk Sun 16 październik 2011, 05:45