LINUX.ORG.RU

Строковое представление класса

 


0

1

Пишу функцию-генератор классов, которая принимает имя нового класса, функцию и возвращает класс. Нужно, чтобы str(myNewClass) возвращал имя класса. Для этого использую метакласс, которые переопределяет метод __repr__ для класса. Все работает на втором питоне, сейчас портирую на третий, но не тут-то было. Код:

import abc

class metaCommand (abc.ABCMeta):
    def __repr__ (self):
        return self._str

def commandFactory (name, function):
    class cls (baseCommand):
        _str = name
        def __init__ (self, **kwargs):
            baseCommand.__init__ (self, name)
    cls.__name__ = name
    return cls

class baseCommand (object):
    __metaclass__ = metaCommand
    @abc.abstractmethod
    def __init__ (self, cmd):
        pass

def scp_function():
    pass

scp = commandFactory ('scp', scp_function)

print (scp)

yunake@x230:~/src/s3do$ python3 test.py
<class '__main__.commandFactory.<locals>.cls'>
yunake@x230:~/src/s3do$ python2 test.py
scp

Получается, py3 использует не __repr__ из метакласса, и не __str__ (тоже пробовал). Есть идеи?

судо каст tailgunner

★★★★★

упростил:

import abc

class metaCommand (abc.ABCMeta):
    def __repr__ (self):
        return self._str

def commandFactory (name):
    class cls (baseCommand):
        _str = name
    return cls

class baseCommand (object):
    __metaclass__ = metaCommand

scp = commandFactory ('scp')

print (scp)

val-amart ★★★★★ ()
Последнее исправление: val-amart (всего исправлений: 1)
Ответ на: комментарий от val-amart
import abc

class metaCommand (abc.ABCMeta):
    def __repr__ (self):
        return self._str

def commandFactory (name):
    class cls (metaclass = metaCommand):
        _str = name
    return cls

scp = commandFactory ('scp')

print (scp)

Не то?

risenshnobel ★★★ ()

Я с третьим питоном дела еще не имел.

Пишу функцию-генератор классов

Лично я защищаюсь кирпичами и булыжниками^W^W^W^Wгенерирую классы функцией type.

c = type("foo", (int,), {})
tailgunner ★★★★★ ()

Кошернее для str переопределять не __repr__, а __str__.
__repr__ берется только, если __str__ не реализован для класса, емнип.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от tailgunner

о! так кстати работает и в 2, и в 3.

Спасибо всем за помощь, проблема решена. Код, который работает и в двойке, и в тройке, выглядит так:

class metaCommandClass (type):
    def __repr__ (self):
        return self._str

metaCommand = metaCommandClass ('metaCommand', (object, ), {})

def commandFactory (name):
    class cls (baseCommand):
        _str = name
    return cls

class baseCommand (metaCommand):
    pass

scp = commandFactory ('scp')

print (scp)
val-amart ★★★★★ ()
Ответ на: комментарий от val-amart
class metaCommandClass (type):
    def __repr__ (cls):
        return cls._str

Пофиксил. Поскольку metaCommandClass наследует от type, это — метакласс (т.к. type это метакласс). Метаклассы оперируют классами, а не инстансами классов. По соглашению, чтобы это различие отобразить, вместо идентификатора «self» используют «cls».

Зачем нужен baseCommand?

Ну и мой вариант:

class metaCommandClass (type):
    def __repr__ (cls):
        return cls.__name__

def commandFactory (name):
    return metaCommandClass (name, (object,), {})

scp = commandFactory ('scp')
print (scp)

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Сам же поправлял и забыл :(. Вместо __repr__ надо __str__ определять.

class metaCommandClass (type):
    def __str__ (cls):
        return cls.__name__
Если задумка была такая, то __repr__:
>>> scp # <==> repr(scp)
scp
>>> print (scp) # <==> str(scp)
scp
>>> 
Если такая, то __str__:
>>> scp
<class '__main__.scp'>
>>> print (scp)
scp
>>> 

Virtuos86 ★★★★★ ()

ret = None
g = {}
name = 'somename'

if not name.isidentifier():
    print("error")
else:
    exec("class {}: pass".format(name), g, g)
    ret = g[name]

return ret

не за что

AGUtilities ★★★ ()

да, к стати, динамически создаваемые классы - не соответствуют правилам питона

AGUtilities ★★★ ()
Ответ на: комментарий от val-amart

Я бы всё же написал

def commandFactory(name):
  return type(name, (baseCommand, ), { "_str": name })

чтобы у класса scp было приличное имя (а не «cls»).

tailgunner ★★★★★ ()
Ответ на: комментарий от tailgunner

Если уж буквоедствовать, то я использую callable object (вызываю метод type.__call__) %)

А ведь у этого метода тоже есть метод _call__, а у того тоже. Вопрос: какой же код всё-таки работает? +)

Какое буквоедство. Ты называешь его функцией, ниже по треду в коде от него наследуют классы — wut??

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

А ведь у этого метода тоже есть метод _call__, а у того тоже. Вопрос: какой же код всё-таки работает? +)

Я вызываю первый, дальше меня не интересует %)

Ты называешь его функцией, ниже по треду в коде от него наследуют классы — wut??

Насколько я понимаю, технически правильный термин - callable object.

tailgunner ★★★★★ ()
Ответ на: комментарий от Virtuos86

Пофиксил.

как хочу, так и называю =P

Зачем нужен baseCommand?

Затем, что нужен. Это же специально упрощенный пример а не весь код.

Вместо __repr__ надо __str__ определять.

кому надо? мне надо репр.

val-amart ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.