Создание экземпляра типа (self) динамически без вызова __init__? - PullRequest
5 голосов
/ 05 ноября 2011

Это довольно сложно объяснить. У меня есть класс, который должен поддерживать метод copy_stateonly(). Он должен вернуть поврежденную версию объекта, которая содержит только (скопированные) элементы данных, которые я хочу. Я надеюсь, что этот пример объясняет это лучше:

# everything inherits from this
class SuperBase:
    def __init__(self):
        self.state_var = 3 # this should be copied into future objects
        self.non_state_var = 0 # we don't want to copy this

    def copy_stateonly(self):
        newobj = # ??????????? create instance without calling __init__
        newobj.state_var = self.state_var
        return newobj

# some clases inherit from this
class Base(SuperBase):
    def __init__(self):
        SuperBase.__init__(self)
        self.isflying = True # we want to copy this, this is state
        self.sprite = "sprites/plane_generic.png" # we must drop this

    def copy_stateonly(self):
        newobj = SuperBase.copy_stateonly(self)
        newobj.isflying = self.isflying
        return newobj

class A144fighter(Base):
    def __init__(self, teamname): # note required __init__ argument
        Base.__init__(self)
        self.colors = ["black", "grey"] # we want to copy this, this is state
        self.name = teamname # we must drop this

    def copy_stateonly(self):
        newobj = Base.copy_stateonly(self)
        newobj.colors = self.colors[:]
        return newobj

plane = A144fighter("team_blue")
plane_state = plane.copy_stateonly() # this should return an A144fighter object with only state_var, flying and colors set.

Python 2.7

Ответы [ 3 ]

7 голосов
/ 05 ноября 2011

Мне не известен способ создания новых экземпляров классических классов (что вы и использовали в своем примере) без вызова __init__(). Новые экземпляры классов нового стиля (потомки object) могут быть созданы с помощью

object.__new__(cls)

где cls - это тип объекта, который вы хотите создать.

В качестве альтернативы можно использовать copy.copy() для копирования, возможно перезаписывая __getstate__() и __setstate__(), чтобы определить, что должно быть скопировано.

Редактировать : Чтобы создать новый экземпляр классического класса cls без вызова __init__(), вы можете использовать следующий хак:

class EmptyClass:
    pass

new_instance = EmptyClass()
new_instance.__class__ = cls
new_instance.__dict__.update(whatever)
2 голосов
/ 05 ноября 2011
# everything inherits from this
class SuperBase:
    def __init__(self):
        self.state_var = 3 # this should be copied into future objects
        self.non_state_var = 0 # we don't want to copy this

    def __getstate__(self):
        return { 'state_var' : self.state_var }

    def __str__(self):
        return self.__class__.__name__ + '(' + str(vars(self)) + ')'

# some clases inherit from this
class Base(SuperBase):
    def __init__(self):
        SuperBase.__init__(self)
        self.isflying = True # we want to copy this, this is state
        self.sprite = "sprites/plane_generic.png" # we must drop this

    def __getstate__(self):
        state = SuperBase.__getstate__(self)
        state['isflying'] = self.isflying
        return state

class A144fighter(Base):
    def __init__(self, teamname): # note required __init__ argument
        Base.__init__(self)
        self.colors = ["black", "grey"] # we want to copy this, this is state
        self.name = teamname # we must drop this

    def __getstate__(self):
        state = Base.__getstate__(self)
        state['colors'] = self.colors[:]
        return state

plane = A144fighter("team_blue")
print plane

import copy
print copy.copy(plane)

# or manually:
import types
print types.InstanceType(plane.__class__, plane.__getstate__())
1 голос
/ 05 ноября 2011

Помните, что у каждого объекта есть атрибут с именем __class__.Если вы сделаете <object>.__class__, он вернет объект класса этого объекта (если это имеет смысл).Объект класса вызывается, поэтому вы можете добавить скобки в конец, чтобы создать новый экземпляр этого класса.

newobj = self.__class__()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...