В этом разница между доступом к имени и привязке в пределах области.
Если вы просто просматриваете переменную, чтобы прочитать ее значение, у вас есть доступ к глобальным и локальным областям.
Однако, если вы назначаете переменной, имя которой не находится в локальной области, вы привязываете это имя в эту область (и если это имя также существует как глобальное, вы это скроете).
Если вы хотите назначить глобальное имя, вам нужно сказать парсеру, чтобы использовать глобальное имя, а не связывать новое локальное имя - это то, что делает ключевое слово «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
>>>
В целом используйте методы фабрики, повышенные как @classmethod
с. Они будут также работать правильно над подклассами. С точки зрения дизайна они являются более явными, особенно при давании хорошего имени.
В этом случае, смешивая все, вероятно, более удобно, но это также делает контракт для Вашего конструктора более трудным.
У Вас могут быть методы фабрики, это прекрасно. Но почему не просто называют его, как это?
Color(r, g, b)
Color(*[r, g, b])
Color(**{'r': r, 'g': g, 'b': b})
Это - Python путь. Что касается из конструктора Object, я предпочел бы что-то как:
Color(*Color2.as_list())
Явный лучше, чем неявный - Дзэн Python
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, способ быть явным и читаемым, плюс он легко позволяет Вам добавлять новые аргументы в случае необходимости.
РЕДАКТИРОВАНИЕ: Плюс я не должен смотреть на фактический код конструктора для понимания аргументов. Объяснение предоставляется ключевым словом.
На эти __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__
для поддержки +=
.
Python всегда полностью заменяет методы тем же именем. В отличие от C#, который, если я помню правильно, сделает методы с теми же опциями имени для другого входа аргумента.
, Если существует только изменение одного в ключевых словах, как или 3 или 4 аргумента того же типа, я сказал бы, что использование предварительной установки последнего аргумента или всех их, будет способом пойти.
Однако, если Вы хотите списки, кортежи и другие типы, необходимо, вероятно, пойти для произвольных аргументов, перечисляют и тестируют содержание этого в функции
def function(*args):
if type(args[0]) is int:
dothis()
#and so on
Можно проверить, что тип аргумента передал конструктору внутри:
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
, Возможно, который поможет.