Импорт методов для класса Python

Комментарий с верхним голосованием в верхнем ответе предполагает, что подход Мартина Анкерла лучше, чем случайные шестнадцатеричные числа, и хотя я не улучшил методологию Анкерла, я успешно перевел его на JavaScript. Я решил опубликовать дополнительный ответ на этот и так мегабаритный SO поток, потому что в верхнем ответе есть еще один комментарий, связанный с Gist с реализацией JS логики Ankerl, и эта ссылка не работает (404). Если бы у меня была репутация, я бы просто прокомментировал созданную мной ссылку jsbin.

// adapted from
// http://jsfiddle.net/Mottie/xcqpF/1/light/
const rgb2hex = (rgb) => {
 return (rgb && rgb.length === 3) ? "#" +
  ("0" + parseInt(rgb[0],10).toString(16)).slice(-2) +
  ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
  ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) : '';
}

// next two methods converted from Ruby to JS
// soured from http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/

// # HSV values in [0..1[
// # returns [r, g, b] values from 0 to 255
const hsv_to_rgb = (h, s, v) => {
  const h_i = Math.floor(h*6)
  const f = h*6 - h_i
  const p = v * (1 - s)
  const q = v * (1 - (f * s))
  const t = v * (1 - (1 - f) * s)
  let r, g, b
  switch(h_i){
    case(0):
      [r, g, b] = [v, t, p]
      break
    case(1):
      [r, g, b] = [q, v, p]
      break
    case(2):
      [r, g, b] = [p, v, t]
      break
    case(3):
      [r, g, b] = [p, q, v]
      break
    case(4):
      [r, g, b] = [t, p, v]
      break
    case(5):
      [r, g, b] = [v, p, q]
      break
  }
  return [Math.floor(r * 256), Math.floor(g * 256), Math.floor(b * 256)]
}

// # use golden ratio
const golden_ratio_conjugate = 0.618033988749895
let h = Math.random() // # use random start value
const gen_hex = (numberOfColors) => {
  const colorArray = []
  while (numberOfColors > 0) {
    h += golden_ratio_conjugate
    h %= 1
    colorArray.push(rgb2hex(hsv_to_rgb(h, 0.99, 0.99)))
    numberOfColors -= 1
  }
  console.log(colorArray)
  return colorArray
}

gen_hex(100)

https://jsbin.com/qeyevoj/edit?js,console

10
задан Martin Gustafsson 29 June 2009 в 12:01
поделиться

8 ответов

Я не думаю, что то, что вы хотите, возможно напрямую в Python.

Вы можете, однако, попробовать одно из следующего:

  1. При генерации to_import_from.py добавьте туда несгенерированный материал. Сюда, все методы находятся в одном и том же определении класса.
  2. Пусть to_import_from.py содержит определение базового класса, которое класс Instrument наследуется.

Другими словами, в to_import_from.py :

class InstrumentBase(object):
    def external_method(self, arg1, arg2):
        if self.flag:
            ...

, а затем в main_module.py :

import to_import_from

class Instrument(to_import_from.InstrumentBase):
    def __init__(self):
        ...
7
ответ дан 3 December 2019 в 14:44
поделиться

Люди, кажется, слишком задумываются над этим. Методы - это просто локальные переменные со значением функции в области построения класса. Итак, следующее работает нормально:

class Instrument(Object):
    # load external methods
    from to_import_from import *

    def __init__(self):
        self.flag = True
    def direct_method(self,arg1):
        self.external_method(arg1, arg2)
10
ответ дан 3 December 2019 в 14:44
поделиться

Это проще, чем вы думаете:

class Instrument(Object):
    def __init__(self):
        self.flag = True
    def direct_method(self,arg1):
        self.external_method(arg1, arg2)

import to_import_from

Instrument.external_method = to_import_from.external_method

Готово!

Хотя создание машинно-сгенерированного кода для генерации определения класса и создания на его основе подклассов было бы более изящным решением.

6
ответ дан 3 December 2019 в 14:44
поделиться

вы можете сделать это с помощью метода __ getattr __

external.py

def external_function(arg):
    print("external", arg)

main.py:

import external

class Instrument(object):
    def __getattr__(self, name):
        if hasattr(external, name):
            return getattr(external, name)
        else:
            return Object.__getattr__(self, name)

    def direct_method(self, arg):
        print("internal", arg)


i = Instrument() 
i.direct_method("foo")
i.external_function("foo")
4
ответ дан 3 December 2019 в 14:44
поделиться

I Мне очень жаль, что это что-то вроде ответа «Вы не должны забивать гвозди в стену» , но вы упускаете суть определений классов python. Вам лучше поместить класс со всеми его методами в отдельный файл python и в ваш main_module.py do

from instrument import Instrument

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

Наконец, дайте вашему классу хорошую строку документации, которая объясняет API его пользователю, так что нет необходимости в "заголовочный файл", используемый в качестве обзора вашего класса.

3
ответ дан 3 December 2019 в 14:44
поделиться

What you '

2
ответ дан 3 December 2019 в 14:44
поделиться

Вот моя попытка. Я думаю, что более удачный подход может быть сделан с помощью метаклассов ...

to_import_from.py:

def external_method(self, arg1, arg2):
    if self.flag:
        print "flag is set"
    else :
        print "flag is not set"

instrument.py:

import imp
import os
import inspect
import new

import pdb

class MethodImporter(object) :
    def __init__(self, path_to_module) :
        self.load_module(path_to_module)

    def load_module(self, path_to_module) :
        name = os.path.basename(path_to_module)
        module_file = file(path_to_module,"r")
        self.module = imp.load_module(name, module_file , path_to_module, ('','r',imp.PY_SOURCE))
        print "Module %s imported" % self.module
        for method_name, method_object in inspect.getmembers(self.module, inspect.isfunction) :
            print "adding method %s to %s" % (method_name, self)
            setattr(self, method_name, new.instancemethod(method_object, self, self.__class__))


class Instrument(MethodImporter):
    def __init__(self):
        super(Instrument,self).__init__("./to_import_from.py")
        self.flag = True
    def direct_method(self,arg1):
        self.external_method(arg1, arg2)

при запуске этого кода

arg1, arg2 = 1, 2
instr = Instrument()
instr.direct_method(arg1)
instr.external_method(arg1, arg2)

вот результат:

Module <module 'to_import_from.py' from './to_import_from.pyc'> imported
adding method external_method to <__main__.Instrument object at 0x2ddeb0>
flag is set
flag is set
0
ответ дан 3 December 2019 в 14:44
поделиться

Технически да, это возможно, но решение этой проблемы таким образом не совсем идиоматический Python, и, вероятно, есть более эффективные решения. Вот пример того, как это сделать:

import to_import_from

class Instrument(object):
    locals().update(dict((k,v) for (k,v) in 
                    to_import_from.__dict__.iteritems() if callable(v)))

    def __init__(self):
        self.flag = True
    def direct_method(self,arg1):
        self.external_method(arg1, arg2)

Это импортирует все вызываемые функции, определенные в to_import_from , как методы класса Instrument , а также добавит еще несколько методов. Примечание: если вы также хотите скопировать глобальные переменные как переменные экземпляра, вам необходимо уточнить проверку. Также обратите внимание, что он добавляет всех вызываемых объектов, которые он находит в пространстве имен to_import_from, включая импорт из других модулей (то есть из импорта модуля в стиле some_func импорта стиля)

Однако это не ужасно хороший способ сделать это. Лучше вместо этого настроить генерацию кода так, чтобы создавал класс, и ваш класс унаследовал от него. Это позволяет избежать ненужного копирования методов в пространство имен инструмента и вместо этого использовать обычное наследование. например:

class Instrument(to_import_from.BaseClass):
    # Add new methods here.
0
ответ дан 3 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: