Как обработать конструкторов или методы с другим набором (или тип) аргументов в Python?

В этом разница между доступом к имени и привязке в пределах области.

Если вы просто просматриваете переменную, чтобы прочитать ее значение, у вас есть доступ к глобальным и локальным областям.

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

Если вы хотите назначить глобальное имя, вам нужно сказать парсеру, чтобы использовать глобальное имя, а не связывать новое локальное имя - это то, что делает ключевое слово «global».

Привязка в любом месте блока приводит к тому, что имя внутри этого блока становится привязанным, что может вызвать некоторые довольно странные последствия (например, UnboundLocalError внезапно появляется в предыдущем рабочем коде).

>>> a = 1
>>> def p():
    print(a) # accessing global scope, no binding going on
>>> def q():
    a = 3 # binding a name in local scope - hiding global
    print(a)
>>> def r():
    print(a) # fail - a is bound to local scope, but not assigned yet
    a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
  File "", line 1, in 
    r()
  File "", line 2, in r
    print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>> 

15
задан Rex M 26 June 2009 в 04:50
поделиться

6 ответов

В целом используйте методы фабрики, повышенные как @classmethod с. Они будут также работать правильно над подклассами. С точки зрения дизайна они являются более явными, особенно при давании хорошего имени.

В этом случае, смешивая все, вероятно, более удобно, но это также делает контракт для Вашего конструктора более трудным.

9
ответ дан 1 December 2019 в 02:29
поделиться

У Вас могут быть методы фабрики, это прекрасно. Но почему не просто называют его, как это?

Color(r, g, b)
Color(*[r, g, b])
Color(**{'r': r, 'g': g, 'b': b})

Это - Python путь. Что касается из конструктора Object, я предпочел бы что-то как:

Color(*Color2.as_list())

Явный лучше, чем неявный - Дзэн Python

10
ответ дан 1 December 2019 в 02:29
поделиться

Python не принимает несколько методов с тем же именем, период. Один метод делает одну вещь.

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

class Color (object):

   def __init__(self, **parms):
      if parms.get('list'):
         self.r, self.g, self.b = parms['list'] 
      elif parms.get('color'):
         color = parms['color']
         self.r = color.r
         self.g = color.g
         self.b = color.b
      else:
         self.r = parms['red']
         self.g = parms['green']
         self.b = parms['blue']

c1 = Color(red=220, green=0, blue=270)
c2 = Color(list=[220, 0, 70])
c3 = Color(color=c1)

Это соответствует Python, способ быть явным и читаемым, плюс он легко позволяет Вам добавлять новые аргументы в случае необходимости.

РЕДАКТИРОВАНИЕ: Плюс я не должен смотреть на фактический код конструктора для понимания аргументов. Объяснение предоставляется ключевым словом.

7
ответ дан 1 December 2019 в 02:29
поделиться

На эти __add__ проблема:

Первый, Вы не можете получить "три целых числа", я предполагаю, что Вы имеете в виду с 3 кортежами из целых чисел?

В этом случае, Вы не обойдете приблизительно isinstance вызовы:

def __add__(self, other):
    if isinstance(other, Color):
        ...
    elif isinstance(other, (int, long)):
        ...
    elif len(other) == 3 and all(isinstance(e, (int, long)) for e in other):
        ...
    else:
        raise TypeError("Can only add Color to Color, int or three-tuple")

Вы могли бы также хотеть добавить реализации __radd__, так, чтобы можно было обработать

1 + Color(1, 2, 3)

, но это всего

def __radd__(self, other):
    return self.__add__(other)

, хотя строго, это никогда не будут называть когда type(other) is Color.

кроме того, не забывайте __iadd__ для поддержки +=.

2
ответ дан 1 December 2019 в 02:29
поделиться

Python всегда полностью заменяет методы тем же именем. В отличие от C#, который, если я помню правильно, сделает методы с теми же опциями имени для другого входа аргумента.

, Если существует только изменение одного в ключевых словах, как или 3 или 4 аргумента того же типа, я сказал бы, что использование предварительной установки последнего аргумента или всех их, будет способом пойти.

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

def function(*args):
    if type(args[0]) is int:
        dothis()
    #and so on
0
ответ дан 1 December 2019 в 02:29
поделиться

Можно проверить, что тип аргумента передал конструктору внутри:

def __init__(self, r = 0, g = 0, b = 0):
    # if r is a list
    if (type(r) == type([1,2,3])):
        r, g, b = r[0], r[1], r[2]
    # if r is a color
    if (type(r) == type(self)):
        r, g, b = r.r, r.g, r.b
    self.r = r
    self.g = g
    self.b = b

, Возможно, который поможет.

-1
ответ дан 1 December 2019 в 02:29
поделиться
Другие вопросы по тегам:

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