Przekazywanie przez referencję

0

Cześć,
Jak można przekazać obiekt do funkcji w klasie przez referencję, czy jest to możliwe, nie bardzo mogę znaleźć informacje na ten temat.....
Problem mam taki, że przekazuje instancję obiektu jakiejś własnej klasy do funkcji w celu wykonania operacji na tym obiekcie. Niestety w funkcji pracuję już na innej instancji, tworzy się kopia, sprawdzałem przy pomocy funkcji id(), czy jest jakiś sposób by przekazać go przez referencje, ewentualnie obejście tego progremu?

0

Możesz pokazać kod? bo to co mówisz kłóci się z moją (niewielką) wiedzą o Pythonie

4

Niestety w funkcji pracuję już na innej instancji, tworzy się kopia

To raczej nie jest prawda

Patrz:

>>> class Foo:
...     def __init__(self):
...             self.bar = 'asd'
... 
>>> x = Foo()
>>> x
<__main__.Foo object at 0x7fbfee9ddd30>
>>> x.bar
'asd'
>>> def modify(o):
...     o.bar = 'spam'
... 
>>> modify(x)
>>> x.bar
'spam'
2

Modyfikujesz pole obiektu, czyli to do czego wskaźnik się odnosi, ale na stosie jest kopia samego obiektu, (referencji do niego) i jego w funkcji, zmienić nie można; dlatego:

class Foo:
    def __init__(self):
        self.f = "bar"

def modify(obj):
    obj = "baz"


f1 = Foo()
print(f1)  # -> <__main__.Foo object at 0x7faeac165910>
modify(f1)
print(f1.f, f1) # ->  bar <__main__.Foo object at 0x7faeac165910>
0

Jestem początkujący w pythonie i pewnie czegoś nie ogarniam. Staram się zrobić pewien mechanizm, który zrobiłem kiedyś w c c#. W skrócie chodzi o to, by załadować dynamicznie klasy pluginów i uruchomić ich instancje tak, by każda działała w osobnym procesie.

  • każda wtyczka może kręcić się nieskończenie długo i bardzo długo nie zwracać wyniku
  • zinstancjownowane wtyczki znajdują się w tablicy __plugin_instances
  • każda wtyczka dziedziczy po pewnej klasie abstrakcyjnej, która ma zapewnić jednolity interfejs (metody init() i run())

W momencie uruchomienia funkcji run_all_by_configuration tablica instancji jest przekazywana do ProcessPoolExecutor, który przy pomocy funkcji launch_plugin uruchamia procesy - w tej funkcji plugin ma już inne id, następnie w uruchamianej cyklicznie funkcji check_plugins() chce kontrolować stan wtyczek ale widzę, że obiekty w __plugin_instances się nie zmieniają. Zakładam, że coś robię nie tak

screenshot-20210217141658.png

class InterfaceManager:
    __plugin_loader: PluginLoader
    __pool_executor: concurrent.futures.ProcessPoolExecutor
    __scheduler: sched.scheduler
    __configuration_tree: []
    __plugin_instances: []
    __workers_number: int
    __scheduler_delay: int

    def __init__(self, configuration_tree):
        self.__plugin_loader = PluginLoader(Parameters.inrastructure_plugins_dir)
        self.__configuration_tree = configuration_tree
        self.__workers_number = len(configuration_tree)
        self.__pool_executor = concurrent.futures.ProcessPoolExecutor(max_workers=self.__workers_number)
        self.__plugin_loader.load_all_plugins()
        self.__scheduler = sched.scheduler(time.time, time.sleep)
        self.__scheduler_delay = Parameters.scheduler_delay_for_im

    def verify_configuration(self) -> bool:
        p_i = [x for x in self.__configuration_tree if
               x.enabled == 1 and
               x.plugin_type.processing_type == Enums.ProcessingType.PROCESSING.value and
               x.plugin_type.manager_type == Enums.ManagerType.INTERFACE.value
               ]
        self.__configuration_tree = p_i

        if len(self.__configuration_tree) > 0:
            return True
        else:
            return False

    def init_by_configuration(self):
        self.__plugin_instances = []
        for conf in self.__configuration_tree:
            pl = self.__plugin_loader.plugins[conf.plugin_type.library_name]
            plugin = pl()
            plugin.init(conf.name, conf.plugin_instance_configurations)
            self.__plugin_instances.append(plugin)
            # print(id(plugin))

    def run_all_by_configuration(self):
        if len(self.__plugin_instances) > 0:
            self.__pool_executor.map(self.launch_plugin, self.__plugin_instances)

        self.__scheduler.enter(self.__scheduler_delay, 1, self.__check_plugins)
        self.__scheduler.run()

    def run_single(self):
        pass

    def __check_plugins(self):
        for plugin_instance in self.__plugin_instances:
            print(id(plugin_instance))
            print('Status dla %s - %s', plugin_instance.instance_name, plugin_instance.is_working)

            # print(dir(plugin_instance))
            # print(id(plugin_instance))

        self.__scheduler.enter(self.__scheduler_delay, 1, self.__check_plugins)

    @classmethod
    def launch_plugin(cls, plugin):  # todo: try catch
        print(id(plugin))
        plugin.run()
2

Jeśli modyfikujesz obiekty w innych procesach, to problem nie leży w przekazywaniu ich do funkcji ;)

Co do zasady procesy nie współdzielą pamięci, każdy będzie miał własną kopię tych obiektów w zaalokowanej dla siebie pamięci i tak dalej.

Co prawda powinno dać się to "ohakować", stosując pamięć współdzieloną - ale wtedy musisz mieć pewność, że procesy z puli będą z niej korzystały i te obiekty musiałyby żyć w pamięci współdzielonej właśnie. Pamiętam, że kiedyś coś takiego robiłem, bo FileLocki sprawiały za dużo problemów, a Pythonowe read/write-locki działały tylko na wątkach. Więc właśnie w oparciu o shared mem wyrzeźbiłem prosty RWLock działający z procesami, także dać się da ;)

https://docs.python.org/3/library/multiprocessing.shared_memory.html
https://stackoverflow.com/a/14135569

1

Tak dla uporządkowania -- w Pythonie wszystko jest przekazywane przez wskaźnik, nie ma przekazywania przez referencję (przynajmniej tak, jak to się rozumie np. w C++).

A więc nie możemy zmienić przekazanego obiektu na inny, ale możemy zmienić jego zawartość...

1 użytkowników online, w tym zalogowanych: 0, gości: 1