Создание глобального экземпляра класса внутри функции

Поэтому я пишу фильтр для программы манипуляции с ландшафтом Minecraft MCEdit. Фильтр написан на Python 2 (это единственное, что MCEdit будет читать). MCEdit вызывает фильтр, передавая уровень переменных (типа MCLevel), блок и параметры в выполнение определенной пользователем функции (уровень, блок, параметры). Вы можете найти документацию по этому здесь >> https://github.com/mcedit/pymclevel

Я написал несколько фильтров раньше, так что я знаю общее представление о том, как это работает. Вот мой код:

from pymclevel import *
import random

inputs = (("Replace", (0, 1, 255)), ("Of Damage", (0, 0, 15)), ("With", (1, 1, 255)), ("Of Damage ", (0, 0, 15)), ("This Percent of the Time", (50, 0, 100)), ("If it is Beside", (False)), ("Or Diagonal", (False)), ("Exclusively", (False)), ("To", (0, 1, 255)), ("Of Damage  ", (0, 0, 15)))

def getBlock(x, y, z):
    global level
    return (level.blockAt(x, y, z), level.blockDataAt(x, y, z))

def setBlock(x, y, z, block, data):
    global level
    level.setBlockAt(x, y, z, block)
    level.setBlockDataAt(x, y, z, data)

def IsBeside(x, y, z, block, data):
    return (getBlock(x - 1, y, z) == (block, data) or getBlock(x + 1, y, z) == (block, data) or getBlock(x, y - 1, z) == (block, data) or getBlock(x, y + 1, z) == (block, data) or getBlock(x, y, z - 1) == (block, data) or getBlock(x, y, z + 1) == (block, data))

def IsDiagonal(x, y, z, block, data):
    return (getBlock(x - 1, y - 1, z) == (block, data) or getBlock(x - 1, y, z - 1) == (block, data) or getBlock(x, y - 1, z - 1) == (block, data) or getBlock(x + 1, y + 1, z) == (block, data) or getBlock(x + 1, y, z + 1) == (block, data) or getBlock(x, y + 1, z + 1) == (block, data) or getBlock(x + 1, y + 1, z + 1) == (block, data) or getBlock(x - 1, y + 1, z + 1) == (block, data) or getBlock(x + 1, y - 1, z + 1) == (block, data) or getBlock(x + 1, y + 1, z - 1) == (block, data) or getBlock(x - 1, y - 1, z + 1) == (block, data) or getBlock(x - 1, y + 1, z - 1) == (block, data) or getBlock(x + 1, y - 1, z - 1) == (block, data) or getBlock(x - 1, y - 1, z - 1) == (block, data))

def perform(level, box, options):

    Replace = options["Replace"]
    ReplaceData = options["Of Damage"]
    With = options["With"]
    WithData = options["Of Damage "]
    Percent = options["This Percent of the Time"]
    Beside = options["If it is Beside"]
    Diagonal = options["Or Diagonal"]
    Exclusive = options["Exclusively"]
    Check = options["To"]
    CheckData = options["Of Damage  "]

    mark = False

    for x in xrange(box.minx, box.maxx + 1):
        for z in xrange(box.minz, box.maxz + 1):
            for y in xrange(box.miny, box.maxy + 1):
                if random.randint(1, 100) <= Percent and getBlock(x, y, z) == (Replace, ReplaceData):

                    if Beside and not Diagonal and not Exclusive:
                        if IsBeside(x, y, z, Check, CheckData):
                            mark = True

                    elif not Beside and Diagonal and not Exclusive:
                        if IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    elif Beside and not Diagonal and Exclusive:
                        if IsBeside(x, y, z, Check, CheckData) and not IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    elif not Beside and Diagonal and Exclusive:
                        if not IsBeside(x, y, z, Check, CheckData) and IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    elif Beside and Diagonal:
                        if IsBeside(x, y, z, Check, CheckData) and IsDiagonal(x, y, z, Check, CheckData):
                            mark = True

                    else:
                        mark = True

                    if mark:
                        level.setBlock(x, y, z, With, WithData)
                        mark = False

Моя проблема в том, что мне нужно вызывать getBlock и setBlock абсурдное количество раз, и вполне вероятно, что уровень будет содержать ОГРОМНОЕ количество информации (достаточно того, что может потребоваться несколько секунд, чтобы просто скопировать его в функцию). По сути, это означает, что фильтр может легко работать в течение нескольких часов, большую часть этого времени занимает только копирование уровня. Естественно, я не хочу этого делать, и поскольку у python нет передачи по ссылке, и я не могу получить доступ к исходной переменной, которая была передана в execute, я могу только попытаться получить доступ к экземпляру уровня, переданного для выполнения из другие функции. Вот где приходит глобальный материал, который, очевидно, не работает. Кто-нибудь знает способ заставить это работать без передачи уровня в качестве аргумента функции для getBlock и setBlock? Мне все равно, использует ли он глобальный или нет, это была только моя мысль.

1 ответ

Решение

Вы запустили этот код и подтвердили, что он на самом деле очень медленный? Python не использует передачу по значению или передачу по ссылке, скорее он использует передачу по назначению для передачи параметров. Поначалу это может быть трудно понять, но для этого есть несколько важных причин. Насколько я понимаю, передача очень больших объектов функциям в Python не так громоздка, как, скажем, в C/C++, потому что вы не копируете данные объекта из одной ячейки памяти в другую, а скорее данные назначения. Я часто слышал, что это называется "передача по ссылке по значению", что означает, что вы передаете ссылку по значению. Это сбивает с толку, и я предпочитаю это объяснение: код как питониста

Если вы хотите изменить содержимое или значение параметров в вызываемом объекте и отразить эти изменения во внешней области, есть несколько способов сделать это. Если параметры всегда изменяемы (например, список), то вы можете изменить их в вызываемом объекте без проблем, пока ваши изменения находятся на месте, например, без переназначений. Если они неизменны, лучше всего вернуть кортеж измененных объектов. Вы также можете взглянуть на другие приемы в статье прохождения по назначению (та же ссылка, что и выше).

Надеюсь, я вас больше не смутил.:) Удачи!

PS Если у вас есть время, прочитайте остальную часть кода, как питониста. Он довольно быстро читается и полон советов, которые сделают ваше кодирование на Python более плавным.

Другие вопросы по тегам