python: путаница с локальным именем класса - PullRequest
1 голос
/ 31 августа 2010

У меня есть следующий код:

def f():
    class XYZ:
        # ...
    cls = type('XXX', (XYZ, ), {})
    # ...
    return cls

Я сейчас использую его следующим образом:

C1 = f()
C2 = f()

и, кажется, работает нормально: C1 - C2 возвращает False, нетконфликт между атрибутами двух классов и т. д.

Вопрос 1

Почему это так?Как это возможно, что C1 и C2 оба показаны как класс

<'__main__.XXX'>

и все же не один и тот же класс?

Вопрос 2

Является лиесть какая-то проблема с тем фактом, что у меня есть два одинаковых имени для двух разных классов?

Вопрос 3

Я хотел бы иметь возможность написать вместо этого:

f('C1')
f('C2')

с тем же эффектом.Возможно ли это?

Вопрос 4

Если я хочу, чтобы C1 выглядел как обычный класс, а не main .XXX, можно лиговорят:

C1.__name__ = '__main__.C1'

Ответы [ 2 ]

2 голосов
/ 31 августа 2010

На самом деле, вам вообще не нужна строка cls = ....

>>> def f():
...     class C:
...         pass
...     return C
... 
>>> f() is f()
False

Причина: class (а также, например, def) определяет новый класс каждый раз, когда онвстречается = каждый раз, когда вызывается функция.

Что касается cls.__name__, то это на самом деле не семантическая разница.Имя полезно для отладки (вы не предоставляете его непосредственно пользователю, не так ли?) И для самоанализа, но это не должно быть проблемой.Но если вы абсолютно хотите иметь разные имена, вы можете изменить cls.__name__ перед возвратом (также обратите внимание, что после C.__name__ = 'foo', C.__name__ == '__main__.foo'!).

На вопрос 3: можно было бы ввестинепосредственно в глобальное пространство имен ... не делайте это.У него нет преимуществ, есть только недостатки: неочевидные побочные эффекты, плохой стиль, тот факт, что это вообще хак и т. Д.

2 голосов
/ 31 августа 2010

Вопрос 3

Чтобы cls.__name__ было чем угодно, (кивком на предложение Делнана)

def f(clsname):
    class XYZ:
        # ...
    XYZ.__name__ = XYZ
    # ...
    return XYZ

Вопрос 1

Причина, по которой c1 is not c2 состоит в том, что они представляют собой два разных объекта, хранятся в двух разных местах в памяти.

Вопрос 4

Попробуйте ответить на вопрос 1 и посмотрите, как это работает для вас

Вопрос 2

Это может усложнить отладку, так как их атрибуты класса __name__ имеют общее значение, и этого достаточно, чтобы избежать усилий. (см. вопрос 3). Я бы сказал, что у них нет одинаковых имен. Один из них называется C1, а другой - C2 (по крайней мере, в той области, которую вы показываете. Если вы передадите их функции, то имя в этой области будет таким же, как имя параметра они прошли через)

На самом деле, я настолько уверен, что у них нет того же имени, что попытка сказать мне иначе может заставить меня включить музыку громче и притвориться, что я вас не слышу.

В ответ на комментарий

Это можно сделать, но это просто неправильно. Я все равно проиллюстрирую, потому что это освещает:

def f(clsname):
    class XYZ(object):
        pass
    XYZ.__name__ = clsname
    globals()[clsname] = XYZ

f('C1')
f('C2')

print C1
print C2

Это просто работает, вставляя класс в глобальный диктант, набираемый clsname. Но какой в ​​этом смысл? Вы можете вставить его в глобальный диктант под любым именем на самом деле, потому что это просто другое задание. Лучше всего просто вернуть класс из функции и позволить вызывающей стороне решить, какое имя дать классу в своей области видимости. У вас все еще есть атрибут __name__ класса, установленный на строку, которую вы передаете функции для отладки.

...